@momo-kits/calculator-keyboard 0.150.2-beta.20-sp.3 → 0.150.2-beta.21
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/android/src/main/java/com/calculatorkeyboard/CalculatorKeyboardPackage.kt +1 -1
- package/android/src/main/java/com/calculatorkeyboard/CustomKeyboardView.kt +25 -46
- package/android/src/main/java/com/calculatorkeyboard/Event.kt +36 -0
- package/android/src/main/java/com/calculatorkeyboard/{RCTInputCalculator.kt → InputCalculatorViewManager.kt} +108 -28
- package/ios/NativeInputCalculator.mm +44 -14
- package/package.json +75 -75
- package/src/{NativeInputCalculatorNativeComponent.ts → InputCalculatorNativeComponent.ts} +8 -2
- package/src/index.tsx +40 -3
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
package com.calculatorkeyboard
|
|
2
2
|
|
|
3
3
|
import android.annotation.SuppressLint
|
|
4
|
+
import android.content.Context
|
|
4
5
|
import android.content.res.ColorStateList
|
|
5
6
|
import android.graphics.Color
|
|
6
7
|
import android.graphics.drawable.GradientDrawable
|
|
@@ -11,8 +12,10 @@ import androidx.constraintlayout.widget.ConstraintLayout
|
|
|
11
12
|
import com.facebook.react.uimanager.ThemedReactContext
|
|
12
13
|
import org.mariuszgromada.math.mxparser.Expression
|
|
13
14
|
import androidx.core.graphics.toColorInt
|
|
14
|
-
import com.calculatorkeyboard.
|
|
15
|
+
import com.calculatorkeyboard.InputCalculatorViewManager.Companion.calculatorHeight
|
|
15
16
|
import com.facebook.react.bridge.Arguments
|
|
17
|
+
import com.facebook.react.bridge.ReactContext
|
|
18
|
+
import com.facebook.react.uimanager.UIManagerHelper
|
|
16
19
|
import com.facebook.react.uimanager.events.RCTEventEmitter
|
|
17
20
|
|
|
18
21
|
@SuppressLint("SetTextI18n", "ViewConstructor")
|
|
@@ -167,45 +170,13 @@ class CustomKeyboardView(
|
|
|
167
170
|
}
|
|
168
171
|
}
|
|
169
172
|
|
|
170
|
-
fun updateButtonColors(color: Int) {
|
|
171
|
-
specialButtonColor = color
|
|
172
|
-
for (i in 0 until childCount) {
|
|
173
|
-
val child = getChildAt(i)
|
|
174
|
-
if (child is Button) {
|
|
175
|
-
val key = child.text.toString()
|
|
176
|
-
if (specialKeys.contains(key)) {
|
|
177
|
-
if (key == "=") {
|
|
178
|
-
child.background = GradientDrawable().apply {
|
|
179
|
-
shape = GradientDrawable.RECTANGLE
|
|
180
|
-
cornerRadius = 24f
|
|
181
|
-
setColor(specialButtonColor)
|
|
182
|
-
}
|
|
183
|
-
} else {
|
|
184
|
-
child.background = GradientDrawable().apply {
|
|
185
|
-
shape = GradientDrawable.RECTANGLE
|
|
186
|
-
cornerRadius = 24f
|
|
187
|
-
setColor(specialButtonColor)
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
child.setTextColor(Color.BLACK)
|
|
191
|
-
}
|
|
192
|
-
} else if (child is ImageButton) {
|
|
193
|
-
child.background = GradientDrawable().apply {
|
|
194
|
-
shape = GradientDrawable.RECTANGLE
|
|
195
|
-
cornerRadius = 24f
|
|
196
|
-
setColor(specialButtonColor)
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
173
|
private fun onKeyPress(key: String, isMainCTAKey: Boolean) {
|
|
203
174
|
if (isMainCTAKey) {
|
|
204
|
-
emitCustomKey()
|
|
175
|
+
emitCustomKey(context)
|
|
205
176
|
return
|
|
206
177
|
}
|
|
207
178
|
|
|
208
|
-
emitKeyPress(key)
|
|
179
|
+
emitKeyPress(context, key)
|
|
209
180
|
when (key) {
|
|
210
181
|
"AC" -> clearText()
|
|
211
182
|
"back" -> onBackSpace()
|
|
@@ -260,19 +231,27 @@ class CustomKeyboardView(
|
|
|
260
231
|
}
|
|
261
232
|
}
|
|
262
233
|
|
|
263
|
-
private fun emitKeyPress(key: String) {
|
|
264
|
-
val reactContext = context as
|
|
265
|
-
val
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
234
|
+
private fun emitKeyPress(context: Context, key: String) {
|
|
235
|
+
val reactContext = context as ReactContext
|
|
236
|
+
val surfaceId = UIManagerHelper.getSurfaceId(reactContext)
|
|
237
|
+
val eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, editText.id)
|
|
238
|
+
val payload =
|
|
239
|
+
Arguments.createMap().apply {
|
|
240
|
+
putString("key", key)
|
|
241
|
+
}
|
|
242
|
+
val event = OnKeyPressEvent(surfaceId, editText.id, payload)
|
|
243
|
+
|
|
244
|
+
eventDispatcher?.dispatchEvent(event)
|
|
270
245
|
}
|
|
271
246
|
|
|
272
|
-
private fun emitCustomKey() {
|
|
273
|
-
val reactContext = context as
|
|
274
|
-
|
|
275
|
-
|
|
247
|
+
private fun emitCustomKey(context: Context) {
|
|
248
|
+
val reactContext = context as ReactContext
|
|
249
|
+
val surfaceId = UIManagerHelper.getSurfaceId(reactContext)
|
|
250
|
+
val eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, editText.id)
|
|
251
|
+
|
|
252
|
+
val event = OnCustomKeyPressEvent(surfaceId, editText.id)
|
|
253
|
+
|
|
254
|
+
eventDispatcher?.dispatchEvent(event)
|
|
276
255
|
}
|
|
277
256
|
|
|
278
257
|
fun setCustomKeyText(text: String) {
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
package com.calculatorkeyboard
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.WritableMap
|
|
4
|
+
import com.facebook.react.uimanager.events.Event
|
|
5
|
+
|
|
6
|
+
class OnChangeEvent(
|
|
7
|
+
surfaceId: Int,
|
|
8
|
+
viewId: Int,
|
|
9
|
+
private val payload: WritableMap
|
|
10
|
+
) : Event<OnChangeEvent>(surfaceId, viewId) {
|
|
11
|
+
override fun getEventName() = "onChange"
|
|
12
|
+
|
|
13
|
+
override fun getEventData() = payload
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
class OnKeyPressEvent(
|
|
17
|
+
surfaceId: Int,
|
|
18
|
+
viewId: Int,
|
|
19
|
+
private val payload: WritableMap
|
|
20
|
+
) : Event<OnChangeEvent>(surfaceId, viewId) {
|
|
21
|
+
override fun getEventName() = "onKeyPress"
|
|
22
|
+
|
|
23
|
+
override fun getEventData() = payload
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
class OnCustomKeyPressEvent(
|
|
27
|
+
surfaceId: Int,
|
|
28
|
+
viewId: Int
|
|
29
|
+
) : Event<OnChangeEvent>(surfaceId, viewId) {
|
|
30
|
+
override fun getEventName() = "onCustomKeyEvent"
|
|
31
|
+
|
|
32
|
+
override fun getEventData() = null
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
@@ -3,25 +3,43 @@ package com.calculatorkeyboard
|
|
|
3
3
|
import android.annotation.SuppressLint
|
|
4
4
|
import android.content.Context
|
|
5
5
|
import android.graphics.Color
|
|
6
|
+
import android.graphics.Typeface
|
|
7
|
+
import android.os.Build
|
|
8
|
+
import android.provider.Settings.Global.putString
|
|
9
|
+
import android.text.Editable
|
|
10
|
+
import android.text.TextWatcher
|
|
6
11
|
import android.view.KeyEvent
|
|
7
12
|
import android.view.inputmethod.InputMethodManager
|
|
8
13
|
import androidx.core.graphics.toColorInt
|
|
9
14
|
import androidx.core.view.ViewCompat
|
|
10
15
|
import androidx.core.view.WindowInsetsCompat
|
|
16
|
+
import androidx.core.widget.addTextChangedListener
|
|
17
|
+
import com.facebook.react.bridge.Arguments
|
|
18
|
+
import com.facebook.react.bridge.ReactContext
|
|
19
|
+
import com.facebook.react.bridge.ReadableArray
|
|
20
|
+
import com.facebook.react.bridge.ReadableMap
|
|
11
21
|
import com.facebook.react.bridge.UiThreadUtil
|
|
22
|
+
import com.facebook.react.module.annotations.ReactModule
|
|
12
23
|
import com.facebook.react.uimanager.PixelUtil.dpToPx
|
|
24
|
+
import com.facebook.react.uimanager.SimpleViewManager
|
|
13
25
|
import com.facebook.react.uimanager.ThemedReactContext
|
|
14
|
-
import com.facebook.react.
|
|
15
|
-
import com.facebook.react.
|
|
26
|
+
import com.facebook.react.uimanager.UIManagerHelper
|
|
27
|
+
import com.facebook.react.uimanager.ViewManagerDelegate
|
|
28
|
+
import com.facebook.react.uimanager.annotations.ReactProp
|
|
29
|
+
import com.facebook.react.uimanager.events.RCTEventEmitter
|
|
16
30
|
import com.facebook.react.viewmanagers.NativeInputCalculatorManagerDelegate
|
|
17
31
|
import com.facebook.react.viewmanagers.NativeInputCalculatorManagerInterface
|
|
18
|
-
import com.facebook.react.
|
|
19
|
-
import
|
|
32
|
+
import com.facebook.react.views.textinput.ReactEditText
|
|
33
|
+
import com.facebook.react.views.textinput.ReactTextInputManager
|
|
34
|
+
|
|
35
|
+
@ReactModule(name = InputCalculatorViewManager.REACT_CLASS)
|
|
36
|
+
class InputCalculatorViewManager : SimpleViewManager<ReactEditText>(), NativeInputCalculatorManagerInterface<ReactEditText> {
|
|
37
|
+
private val delegate: NativeInputCalculatorManagerDelegate<ReactEditText, InputCalculatorViewManager> =
|
|
38
|
+
NativeInputCalculatorManagerDelegate(this)
|
|
20
39
|
|
|
21
|
-
|
|
22
|
-
class InputCalculatorManager : ReactTextInputManager(), NativeInputCalculatorManagerInterface<ReactEditText> {
|
|
40
|
+
override fun getDelegate(): ViewManagerDelegate<ReactEditText> = delegate
|
|
23
41
|
|
|
24
|
-
|
|
42
|
+
override fun getName() = REACT_CLASS
|
|
25
43
|
|
|
26
44
|
private var keyboardView: CustomKeyboardView? = null
|
|
27
45
|
private lateinit var editText: CalculatorEditText
|
|
@@ -32,14 +50,14 @@ class InputCalculatorManager : ReactTextInputManager(), NativeInputCalculatorMan
|
|
|
32
50
|
private var backListenerAttached = false
|
|
33
51
|
private var overlayShowing = false
|
|
34
52
|
|
|
35
|
-
override fun getName() = REACT_CLASS
|
|
36
53
|
|
|
37
54
|
companion object {
|
|
38
55
|
const val REACT_CLASS = "NativeInputCalculator"
|
|
39
56
|
val calculatorHeight: Int = 240.dpToPx().toInt()
|
|
40
57
|
}
|
|
41
58
|
|
|
42
|
-
|
|
59
|
+
@ReactProp(name = "value")
|
|
60
|
+
override fun setValue(view: ReactEditText, value: String?) {
|
|
43
61
|
UiThreadUtil.runOnUiThread {
|
|
44
62
|
val e = view.editableText ?: run { view.setText(value ?: ""); return@runOnUiThread }
|
|
45
63
|
val newText = value ?: ""
|
|
@@ -52,28 +70,72 @@ class InputCalculatorManager : ReactTextInputManager(), NativeInputCalculatorMan
|
|
|
52
70
|
}
|
|
53
71
|
}
|
|
54
72
|
|
|
55
|
-
override fun
|
|
73
|
+
override fun setTextAttributes(view: ReactEditText?, value: ReadableMap?) {
|
|
74
|
+
val fontWeightStr = value?.getString("fontWeight")
|
|
75
|
+
val fontSize = value?.getDouble("fontSize")
|
|
76
|
+
|
|
77
|
+
fontWeightStr?.let { weightStr ->
|
|
78
|
+
val weight = when (weightStr) {
|
|
79
|
+
"100" -> 100
|
|
80
|
+
"200" -> 200
|
|
81
|
+
"300" -> 300
|
|
82
|
+
"400", "normal" -> 400
|
|
83
|
+
"500" -> 500
|
|
84
|
+
"600" -> 600
|
|
85
|
+
"700", "bold" -> 700
|
|
86
|
+
"800" -> 800
|
|
87
|
+
"900" -> 900
|
|
88
|
+
else -> 400
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
|
92
|
+
view?.typeface = Typeface.create(view.typeface, weight, false)
|
|
93
|
+
} else {
|
|
94
|
+
view?.typeface = if (weight >= 600) {
|
|
95
|
+
Typeface.create(view.typeface, Typeface.BOLD)
|
|
96
|
+
} else {
|
|
97
|
+
Typeface.create(view.typeface, Typeface.NORMAL)
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
fontSize?.let {
|
|
103
|
+
view?.textSize = it.toFloat()
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
@ReactProp(name = "mode")
|
|
109
|
+
override fun setMode(view: ReactEditText, mode: String?) {
|
|
56
110
|
keyboardView?.setMode(mode ?: "NumDefault")
|
|
57
111
|
}
|
|
58
112
|
|
|
59
|
-
|
|
113
|
+
@ReactProp(name = "customKeyText")
|
|
114
|
+
override fun setCustomKeyText(view: ReactEditText, text: String?) {
|
|
60
115
|
keyboardView?.setCustomKeyText(text ?: "Tiếp")
|
|
61
116
|
}
|
|
62
117
|
|
|
63
|
-
|
|
118
|
+
@ReactProp(name = "customKeyBackground")
|
|
119
|
+
override fun setCustomKeyBackground(view: ReactEditText, background: String?) {
|
|
64
120
|
keyboardView?.setCustomKeyBackground((background ?: "#d8d8d8").toColorInt())
|
|
65
121
|
}
|
|
66
122
|
|
|
67
|
-
|
|
123
|
+
@ReactProp(name = "customKeyTextColor")
|
|
124
|
+
override fun setCustomKeyTextColor(view: ReactEditText, textColor: String?) {
|
|
68
125
|
keyboardView?.setCustomKeyTextColor(textColor?.toColorInt() ?: Color.BLACK)
|
|
69
126
|
}
|
|
70
127
|
|
|
71
|
-
|
|
128
|
+
@ReactProp(name = "customKeyState")
|
|
129
|
+
override fun setCustomKeyState(view: ReactEditText, state: String?) {
|
|
72
130
|
keyboardView?.setCustomKeyState(state ?: "default")
|
|
73
131
|
}
|
|
74
132
|
|
|
75
|
-
override fun
|
|
76
|
-
|
|
133
|
+
override fun focus(view: ReactEditText?) {
|
|
134
|
+
UiThreadUtil.runOnUiThread { if (!editText.isFocused) editText.requestFocus() }
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
override fun blur(view: ReactEditText?) {
|
|
138
|
+
UiThreadUtil.runOnUiThread { if (editText.isFocused) editText.clearFocus() }
|
|
77
139
|
}
|
|
78
140
|
|
|
79
141
|
@SuppressLint("ClickableViewAccessibility")
|
|
@@ -104,6 +166,16 @@ class InputCalculatorManager : ReactTextInputManager(), NativeInputCalculatorMan
|
|
|
104
166
|
}
|
|
105
167
|
false
|
|
106
168
|
}
|
|
169
|
+
addTextChangedListener(object : TextWatcher{
|
|
170
|
+
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
|
|
171
|
+
|
|
172
|
+
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
|
|
173
|
+
|
|
174
|
+
override fun afterTextChanged(s: Editable?) {
|
|
175
|
+
emitOnChange(context, s.toString())
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
})
|
|
107
179
|
}
|
|
108
180
|
|
|
109
181
|
keyboardView = CustomKeyboardView(context, editText).apply {
|
|
@@ -168,23 +240,31 @@ class InputCalculatorManager : ReactTextInputManager(), NativeInputCalculatorMan
|
|
|
168
240
|
v.showSoftInputOnFocus = true
|
|
169
241
|
}
|
|
170
242
|
|
|
171
|
-
|
|
243
|
+
private fun emitOnChange(context: Context, text: String) {
|
|
244
|
+
val reactContext = context as ReactContext
|
|
245
|
+
val surfaceId = UIManagerHelper.getSurfaceId(reactContext)
|
|
246
|
+
val eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, editText.id)
|
|
247
|
+
val payload =
|
|
248
|
+
Arguments.createMap().apply {
|
|
249
|
+
putString("text", text)
|
|
250
|
+
}
|
|
251
|
+
val event = OnChangeEvent(surfaceId, editText.id, payload)
|
|
172
252
|
|
|
173
|
-
|
|
174
|
-
UiThreadUtil.runOnUiThread { if (!editText.isFocused) editText.requestFocus() }
|
|
253
|
+
eventDispatcher?.dispatchEvent(event)
|
|
175
254
|
}
|
|
176
255
|
|
|
177
|
-
override fun
|
|
178
|
-
|
|
256
|
+
override fun getExportedCustomBubblingEventTypeConstants(): MutableMap<String, Any> {
|
|
257
|
+
val base = super.getExportedCustomBubblingEventTypeConstants()?.toMutableMap() ?: mutableMapOf()
|
|
258
|
+
base["onKeyPress"] = mapOf("phasedRegistrationNames" to mapOf("bubbled" to "onKeyPress"))
|
|
259
|
+
base["onChange"] = mapOf("phasedRegistrationNames" to mapOf("bubbled" to "onChange"))
|
|
260
|
+
return base
|
|
179
261
|
}
|
|
180
262
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
263
|
+
override fun getExportedCustomDirectEventTypeConstants(): MutableMap<String, Any> {
|
|
264
|
+
val base = super.getExportedCustomDirectEventTypeConstants()?.toMutableMap() ?: mutableMapOf()
|
|
265
|
+
base["onCustomKeyEvent"] = mapOf("registrationName" to "onCustomKeyEvent")
|
|
266
|
+
return base
|
|
185
267
|
}
|
|
186
268
|
|
|
187
|
-
private fun blur() {
|
|
188
|
-
UiThreadUtil.runOnUiThread { if (editText.isFocused) editText.clearFocus() }
|
|
189
|
-
}
|
|
190
269
|
}
|
|
270
|
+
|
|
@@ -24,21 +24,21 @@ using namespace facebook::react;
|
|
|
24
24
|
if (self = [super initWithFrame:frame]) {
|
|
25
25
|
static const auto defaultProps = std::make_shared<const NativeInputCalculatorProps>();
|
|
26
26
|
_props = defaultProps;
|
|
27
|
-
|
|
27
|
+
|
|
28
28
|
// Create text field
|
|
29
29
|
_textField = [[UITextField alloc] initWithFrame:self.bounds];
|
|
30
30
|
_textField.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
|
31
31
|
_textField.delegate = (id<UITextFieldDelegate>)self;
|
|
32
|
-
|
|
32
|
+
|
|
33
33
|
// Create keyboard view
|
|
34
34
|
CGFloat bottomInset = [self getBottomInset];
|
|
35
35
|
CGRect keyboardFrame = CGRectMake(0, 0, UIScreen.mainScreen.bounds.size.width, 240 + bottomInset);
|
|
36
36
|
_keyboardView = [[CalculatorKeyboardView alloc] initWithFrame:keyboardFrame];
|
|
37
37
|
_keyboardView.input = (id)self; // Bridge pattern
|
|
38
|
-
|
|
38
|
+
|
|
39
39
|
// Set custom keyboard
|
|
40
40
|
_textField.inputView = _keyboardView;
|
|
41
|
-
|
|
41
|
+
|
|
42
42
|
[self addSubview:_textField];
|
|
43
43
|
}
|
|
44
44
|
return self;
|
|
@@ -62,7 +62,7 @@ using namespace facebook::react;
|
|
|
62
62
|
{
|
|
63
63
|
const auto &oldViewProps = *std::static_pointer_cast<const NativeInputCalculatorProps>(_props);
|
|
64
64
|
const auto &newViewProps = *std::static_pointer_cast<const NativeInputCalculatorProps>(props);
|
|
65
|
-
|
|
65
|
+
|
|
66
66
|
// Update value
|
|
67
67
|
if (oldViewProps.value != newViewProps.value) {
|
|
68
68
|
NSString *newValue = RCTNSStringFromString(newViewProps.value);
|
|
@@ -71,35 +71,65 @@ using namespace facebook::react;
|
|
|
71
71
|
_lastValue = newValue;
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
|
-
|
|
74
|
+
|
|
75
75
|
// Update mode
|
|
76
76
|
if (oldViewProps.mode != newViewProps.mode) {
|
|
77
77
|
_keyboardView.keyboardMode = RCTNSStringFromString(newViewProps.mode);
|
|
78
78
|
}
|
|
79
|
-
|
|
79
|
+
|
|
80
80
|
// Update customKeyText
|
|
81
81
|
if (oldViewProps.customKeyText != newViewProps.customKeyText) {
|
|
82
82
|
_keyboardView.customKeyText = RCTNSStringFromString(newViewProps.customKeyText);
|
|
83
83
|
}
|
|
84
|
-
|
|
84
|
+
|
|
85
85
|
// Update customKeyBackground
|
|
86
86
|
if (oldViewProps.customKeyBackground != newViewProps.customKeyBackground) {
|
|
87
87
|
_keyboardView.customKeyBackground = RCTNSStringFromString(newViewProps.customKeyBackground);
|
|
88
88
|
}
|
|
89
|
-
|
|
89
|
+
|
|
90
90
|
// Update customKeyTextColor
|
|
91
91
|
if (oldViewProps.customKeyTextColor != newViewProps.customKeyTextColor) {
|
|
92
92
|
_keyboardView.customKeyTextColor = RCTNSStringFromString(newViewProps.customKeyTextColor);
|
|
93
93
|
}
|
|
94
|
-
|
|
94
|
+
|
|
95
95
|
// Update customKeyState
|
|
96
96
|
if (oldViewProps.customKeyState != newViewProps.customKeyState) {
|
|
97
97
|
_keyboardView.customKeyState = RCTNSStringFromString(newViewProps.customKeyState);
|
|
98
98
|
}
|
|
99
|
-
|
|
99
|
+
|
|
100
|
+
// ===== textAttributes (fontSize, fontWeight) =====
|
|
101
|
+
// Codegen should have a prop like: std::optional<folly::dynamic> textAttributes;
|
|
102
|
+
if (oldViewProps.textAttributes.fontSize != newViewProps.textAttributes.fontSize > 0.0f) {
|
|
103
|
+
CGFloat newSize = (CGFloat)newViewProps.textAttributes.fontSize;
|
|
104
|
+
UIFont *current = _textField.font ?: [UIFont systemFontOfSize:UIFont.systemFontSize];
|
|
105
|
+
_textField.font = [current fontWithSize:newSize];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (oldViewProps.textAttributes.fontWeight != newViewProps.textAttributes.fontWeight) {
|
|
109
|
+
UIFontWeight weight = _UIFontWeightFromString(newViewProps.textAttributes.fontWeight);
|
|
110
|
+
CGFloat size = _textField.font ? _textField.font.pointSize : UIFont.systemFontSize;
|
|
111
|
+
_textField.font = [UIFont systemFontOfSize:size weight:weight];
|
|
112
|
+
}
|
|
113
|
+
|
|
100
114
|
[super updateProps:props oldProps:oldProps];
|
|
101
115
|
}
|
|
102
116
|
|
|
117
|
+
static UIFontWeight _UIFontWeightFromString(std::string_view s) {
|
|
118
|
+
std::string v(s);
|
|
119
|
+
for (auto &c : v) c = (char)tolower((unsigned char)c);
|
|
120
|
+
|
|
121
|
+
if (v == "normal" || v == "400") return UIFontWeightRegular;
|
|
122
|
+
if (v == "bold" || v == "700") return UIFontWeightBold;
|
|
123
|
+
if (v == "100") return UIFontWeightUltraLight;
|
|
124
|
+
if (v == "200") return UIFontWeightThin;
|
|
125
|
+
if (v == "300") return UIFontWeightLight;
|
|
126
|
+
if (v == "500") return UIFontWeightMedium;
|
|
127
|
+
if (v == "600") return UIFontWeightSemibold;
|
|
128
|
+
if (v == "800") return UIFontWeightHeavy;
|
|
129
|
+
if (v == "900") return UIFontWeightBlack;
|
|
130
|
+
return UIFontWeightRegular;
|
|
131
|
+
}
|
|
132
|
+
|
|
103
133
|
- (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args
|
|
104
134
|
{
|
|
105
135
|
RCTNativeInputCalculatorHandleCommand(self, commandName, args);
|
|
@@ -143,11 +173,11 @@ using namespace facebook::react;
|
|
|
143
173
|
{
|
|
144
174
|
NSString *text = [_textField.text stringByReplacingOccurrencesOfString:@"×" withString:@"*"];
|
|
145
175
|
text = [text stringByReplacingOccurrencesOfString:@"÷" withString:@"/"];
|
|
146
|
-
|
|
176
|
+
|
|
147
177
|
NSString *pattern = @"^\\s*(-?\\d+(\\.\\d+)?\\s*[-+*/]\\s*)*-?\\d+(\\.\\d+)?\\s*$";
|
|
148
178
|
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:nil];
|
|
149
179
|
NSRange range = NSMakeRange(0, text.length);
|
|
150
|
-
|
|
180
|
+
|
|
151
181
|
if ([regex firstMatchInString:text options:0 range:range]) {
|
|
152
182
|
NSExpression *expression = [NSExpression expressionWithFormat:text];
|
|
153
183
|
id result = [expression expressionValueWithObject:nil context:nil];
|
|
@@ -181,7 +211,7 @@ using namespace facebook::react;
|
|
|
181
211
|
- (void)notifyTextChange
|
|
182
212
|
{
|
|
183
213
|
_lastValue = _textField.text;
|
|
184
|
-
|
|
214
|
+
|
|
185
215
|
if (_eventEmitter) {
|
|
186
216
|
auto emitter = std::static_pointer_cast<const NativeInputCalculatorEventEmitter>(_eventEmitter);
|
|
187
217
|
NativeInputCalculatorEventEmitter::OnChange event{
|
package/package.json
CHANGED
|
@@ -1,77 +1,77 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
},
|
|
33
|
-
"keywords": [
|
|
34
|
-
"react-native",
|
|
35
|
-
"ios",
|
|
36
|
-
"android"
|
|
37
|
-
],
|
|
38
|
-
"repository": {
|
|
39
|
-
"type": "git",
|
|
40
|
-
"url": "git+https://github.com/wem2017/react-native-calculator-keyboard.git/react-native-calculator-keyboard.git"
|
|
41
|
-
},
|
|
42
|
-
"author": "Dũng (Wem) <huynh.developer@gmail.com> (https://github.com/wem2017/react-native-calculator-keyboard.git)",
|
|
43
|
-
"license": "MIT",
|
|
44
|
-
"bugs": {
|
|
45
|
-
"url": "https://github.com/wem2017/react-native-calculator-keyboard.git/react-native-calculator-keyboard/issues"
|
|
46
|
-
},
|
|
47
|
-
"homepage": "https://github.com/wem2017/react-native-calculator-keyboard.git/react-native-calculator-keyboard#readme",
|
|
48
|
-
"publishConfig": {
|
|
49
|
-
"registry": "https://registry.npmjs.org/"
|
|
50
|
-
},
|
|
51
|
-
"codegenConfig": {
|
|
52
|
-
"name": "CalculatorKeyboardSpecs",
|
|
53
|
-
"type": "all",
|
|
54
|
-
"jsSrcsDir": "src",
|
|
55
|
-
"android": {
|
|
56
|
-
"javaPackageName": "com.calculatorkeyboard"
|
|
2
|
+
"name": "@momo-kits/calculator-keyboard",
|
|
3
|
+
"version": "0.150.2-beta.21",
|
|
4
|
+
"description": "react native calculator keyboard",
|
|
5
|
+
"main": "./src/index.tsx",
|
|
6
|
+
"files": [
|
|
7
|
+
"src",
|
|
8
|
+
"lib",
|
|
9
|
+
"android",
|
|
10
|
+
"ios",
|
|
11
|
+
"cpp",
|
|
12
|
+
"*.podspec",
|
|
13
|
+
"react-native.config.js",
|
|
14
|
+
"!ios/build",
|
|
15
|
+
"!android/build",
|
|
16
|
+
"!android/gradle",
|
|
17
|
+
"!android/gradlew",
|
|
18
|
+
"!android/gradlew.bat",
|
|
19
|
+
"!android/local.properties",
|
|
20
|
+
"!**/__tests__",
|
|
21
|
+
"!**/__fixtures__",
|
|
22
|
+
"!**/__mocks__",
|
|
23
|
+
"!**/.*"
|
|
24
|
+
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"test": "jest",
|
|
27
|
+
"typecheck": "tsc",
|
|
28
|
+
"lint": "eslint \"**/*.{js,ts,tsx}\"",
|
|
29
|
+
"clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib",
|
|
30
|
+
"build": "echo",
|
|
31
|
+
"release": "release-it"
|
|
57
32
|
},
|
|
58
|
-
"
|
|
59
|
-
|
|
60
|
-
"
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
"
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
33
|
+
"keywords": [
|
|
34
|
+
"react-native",
|
|
35
|
+
"ios",
|
|
36
|
+
"android"
|
|
37
|
+
],
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "git+https://github.com/wem2017/react-native-calculator-keyboard.git/react-native-calculator-keyboard.git"
|
|
41
|
+
},
|
|
42
|
+
"author": "Dũng (Wem) <huynh.developer@gmail.com> (https://github.com/wem2017/react-native-calculator-keyboard.git)",
|
|
43
|
+
"license": "MIT",
|
|
44
|
+
"bugs": {
|
|
45
|
+
"url": "https://github.com/wem2017/react-native-calculator-keyboard.git/react-native-calculator-keyboard/issues"
|
|
46
|
+
},
|
|
47
|
+
"homepage": "https://github.com/wem2017/react-native-calculator-keyboard.git/react-native-calculator-keyboard#readme",
|
|
48
|
+
"publishConfig": {
|
|
49
|
+
"registry": "https://registry.npmjs.org/"
|
|
50
|
+
},
|
|
51
|
+
"codegenConfig": {
|
|
52
|
+
"name": "CalculatorKeyboardSpecs",
|
|
53
|
+
"type": "components",
|
|
54
|
+
"jsSrcsDir": "src",
|
|
55
|
+
"android": {
|
|
56
|
+
"javaPackageName": "com.calculatorkeyboard"
|
|
57
|
+
},
|
|
58
|
+
"ios": {
|
|
59
|
+
"componentProvider": {
|
|
60
|
+
"NativeInputCalculator": "NativeInputCalculator"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"devDependencies": {
|
|
65
|
+
"react": "*",
|
|
66
|
+
"react-native": "*"
|
|
67
|
+
},
|
|
68
|
+
"peerDependencies": {
|
|
69
|
+
"react": "*",
|
|
70
|
+
"react-native": "*",
|
|
71
|
+
"@momo-kits/foundation": "latest"
|
|
72
|
+
},
|
|
73
|
+
"engines": {
|
|
74
|
+
"node": ">=18.0.0"
|
|
75
|
+
},
|
|
76
|
+
"dependencies": {}
|
|
77
|
+
}
|
|
@@ -26,15 +26,21 @@ export type OnChangeEvent = Readonly<{
|
|
|
26
26
|
text: string;
|
|
27
27
|
}>;
|
|
28
28
|
|
|
29
|
+
export type TextAttributes = Readonly<{
|
|
30
|
+
fontSize?: CodegenTypes.Float;
|
|
31
|
+
fontWeight?: string;
|
|
32
|
+
}>;
|
|
33
|
+
|
|
29
34
|
export interface NativeInputCalculatorProps extends ViewProps {
|
|
30
35
|
value?: string;
|
|
36
|
+
textAttributes?: TextAttributes;
|
|
31
37
|
mode?: string;
|
|
32
38
|
customKeyText?: string;
|
|
33
39
|
customKeyBackground?: string;
|
|
34
40
|
customKeyTextColor?: string;
|
|
35
41
|
customKeyState?: string;
|
|
36
|
-
onChange?: CodegenTypes.
|
|
37
|
-
onKeyPress?: CodegenTypes.
|
|
42
|
+
onChange?: CodegenTypes.BubblingEventHandler<OnChangeEvent>;
|
|
43
|
+
onKeyPress?: CodegenTypes.BubblingEventHandler<OnKeyPressEvent>;
|
|
38
44
|
onCustomKeyEvent?: CodegenTypes.DirectEventHandler<{}>;
|
|
39
45
|
}
|
|
40
46
|
|
package/src/index.tsx
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { useContext } from 'react';
|
|
3
3
|
import { ApplicationContext, Colors } from '@momo-kits/foundation';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
import {
|
|
5
|
+
type NativeSyntheticEvent,
|
|
6
|
+
type TextInputProps,
|
|
7
|
+
StyleSheet,
|
|
8
|
+
StyleProp,
|
|
9
|
+
TextStyle,
|
|
10
|
+
} from 'react-native';
|
|
11
|
+
import NativeInputCalculator, {
|
|
12
|
+
TextAttributes,
|
|
13
|
+
} from './InputCalculatorNativeComponent';
|
|
14
|
+
import { Commands } from './InputCalculatorNativeComponent';
|
|
7
15
|
|
|
8
16
|
const NativeInput = NativeInputCalculator;
|
|
9
17
|
|
|
@@ -17,6 +25,7 @@ interface InputCalculatorProps extends TextInputProps {
|
|
|
17
25
|
customKeyBackground?: CustomKeyBackground;
|
|
18
26
|
customKeyState?: CustomKeyState;
|
|
19
27
|
onCustomKeyEvent?: () => void;
|
|
28
|
+
style?: StyleProp<TextStyle>;
|
|
20
29
|
}
|
|
21
30
|
|
|
22
31
|
export type CustomKeyBackground = 'primary' | 'default' | string;
|
|
@@ -36,6 +45,26 @@ export type InputCalculatorRef = {
|
|
|
36
45
|
blur: () => void;
|
|
37
46
|
};
|
|
38
47
|
|
|
48
|
+
const omitUndefined = <T extends object>(obj: T): T =>
|
|
49
|
+
Object.fromEntries(
|
|
50
|
+
Object.entries(obj).filter(([, v]) => v !== undefined),
|
|
51
|
+
) as T;
|
|
52
|
+
|
|
53
|
+
function isEmpty(obj: object | undefined | null) {
|
|
54
|
+
return !obj || Object.keys(obj).length === 0;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function styleToTextAttributes(
|
|
58
|
+
style?: StyleProp<TextStyle>,
|
|
59
|
+
): Readonly<TextAttributes> {
|
|
60
|
+
const s = StyleSheet.flatten(style) ?? {};
|
|
61
|
+
const attrs: TextAttributes = {
|
|
62
|
+
fontSize: s.fontSize ?? undefined,
|
|
63
|
+
fontWeight: (s.fontWeight as TextAttributes['fontWeight']) ?? undefined,
|
|
64
|
+
};
|
|
65
|
+
return Object.freeze(omitUndefined(attrs));
|
|
66
|
+
}
|
|
67
|
+
|
|
39
68
|
const InputCalculator = React.forwardRef<
|
|
40
69
|
InputCalculatorRef,
|
|
41
70
|
InputCalculatorProps
|
|
@@ -48,6 +77,7 @@ const InputCalculator = React.forwardRef<
|
|
|
48
77
|
onKeyPress,
|
|
49
78
|
customKeyState = CustomKeyState.Default,
|
|
50
79
|
onCustomKeyEvent,
|
|
80
|
+
style,
|
|
51
81
|
...props
|
|
52
82
|
},
|
|
53
83
|
ref,
|
|
@@ -86,9 +116,16 @@ const InputCalculator = React.forwardRef<
|
|
|
86
116
|
},
|
|
87
117
|
}));
|
|
88
118
|
|
|
119
|
+
const derivedTA = React.useMemo(
|
|
120
|
+
() => styleToTextAttributes(style),
|
|
121
|
+
[style],
|
|
122
|
+
);
|
|
123
|
+
|
|
89
124
|
return (
|
|
90
125
|
<NativeInput
|
|
91
126
|
{...props}
|
|
127
|
+
style={style}
|
|
128
|
+
textAttributes={isEmpty(derivedTA) ? undefined : derivedTA}
|
|
92
129
|
ref={nativeRef}
|
|
93
130
|
onChange={_onChange}
|
|
94
131
|
onKeyPress={onKeyPress}
|