@momo-kits/calculator-keyboard 0.150.2-beta80.1 → 0.150.2-phuc.15
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/CustomKeyboardView.kt +99 -40
- package/android/src/main/java/com/calculatorkeyboard/KeyboardOverplayHost.kt +232 -0
- package/android/src/main/java/com/calculatorkeyboard/RCTInputCalculator.kt +112 -94
- package/ios/CalculatorKeyboardView.swift +53 -15
- package/ios/InputCalculator.m +6 -0
- package/ios/InputCalculator.swift +30 -10
- package/lib/commonjs/index.js +26 -2
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/index.js +27 -4
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/commonjs/src/index.d.ts +11 -1
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
- package/lib/typescript/module/src/index.d.ts +11 -1
- package/lib/typescript/module/src/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/index.tsx +46 -7
|
@@ -9,12 +9,12 @@ import android.widget.Button
|
|
|
9
9
|
import android.widget.ImageButton
|
|
10
10
|
import androidx.appcompat.app.AppCompatActivity
|
|
11
11
|
import androidx.constraintlayout.widget.ConstraintLayout
|
|
12
|
-
import androidx.core.graphics.ColorUtils
|
|
13
12
|
import com.facebook.react.uimanager.ThemedReactContext
|
|
14
13
|
import org.mariuszgromada.math.mxparser.Expression
|
|
15
14
|
import androidx.core.graphics.toColorInt
|
|
16
|
-
import com.
|
|
17
|
-
|
|
15
|
+
import com.calculatorkeyboard.RCTInputCalculator.Companion.calculatorHeight
|
|
16
|
+
import com.facebook.react.bridge.Arguments
|
|
17
|
+
import com.facebook.react.uimanager.events.RCTEventEmitter
|
|
18
18
|
|
|
19
19
|
@SuppressLint("SetTextI18n", "ViewConstructor")
|
|
20
20
|
class CustomKeyboardView(
|
|
@@ -22,22 +22,32 @@ class CustomKeyboardView(
|
|
|
22
22
|
private val editText: CalculatorEditText
|
|
23
23
|
) : ConstraintLayout(context) {
|
|
24
24
|
private val keys = listOf(
|
|
25
|
-
listOf("
|
|
26
|
-
listOf("
|
|
27
|
-
listOf("
|
|
28
|
-
listOf("
|
|
29
|
-
listOf("000", "0")
|
|
25
|
+
listOf("1", "2", "3", "÷", "back"),
|
|
26
|
+
listOf("4", "5", "6", "×", "="),
|
|
27
|
+
listOf("7", "8", "9", "-", "Xong"),
|
|
28
|
+
listOf("000", "0", "+")
|
|
30
29
|
)
|
|
31
|
-
private val specialKeys = listOf("=", "-", "×", "÷", "
|
|
30
|
+
private val specialKeys = listOf("=", "-", "×", "÷", "back", "+")
|
|
32
31
|
private val separatorWidth = 8f
|
|
33
32
|
private var specialButtonColor: Int = "#D8D8D8".toColorInt()
|
|
34
33
|
|
|
34
|
+
private var customKeyButton: Button? = null
|
|
35
|
+
private var customKeyButtonBackground: Int = "#D8D8D8".toColorInt()
|
|
36
|
+
private var customKeyButtonTextColor: Int = Color.BLACK
|
|
37
|
+
private var customKeyButtonState: String = "default"
|
|
38
|
+
|
|
35
39
|
init {
|
|
36
40
|
val activity = context.currentActivity as? AppCompatActivity
|
|
37
41
|
if (activity != null) {
|
|
38
42
|
val displayMetrics = resources.displayMetrics
|
|
39
|
-
val widthButton = (displayMetrics.widthPixels - separatorWidth * 2 -
|
|
40
|
-
val heightButton = (
|
|
43
|
+
val widthButton = (displayMetrics.widthPixels - separatorWidth * 2 - 4 * separatorWidth) / 5f
|
|
44
|
+
val heightButton = (calculatorHeight - separatorWidth * 2 - 3 * separatorWidth) / 4
|
|
45
|
+
|
|
46
|
+
isClickable = false
|
|
47
|
+
isFocusable = false
|
|
48
|
+
isFocusableInTouchMode = false
|
|
49
|
+
clipToPadding = false
|
|
50
|
+
clipChildren = false
|
|
41
51
|
|
|
42
52
|
renderUI(widthButton, heightButton)
|
|
43
53
|
}
|
|
@@ -46,16 +56,19 @@ class CustomKeyboardView(
|
|
|
46
56
|
|
|
47
57
|
private fun renderUI(buttonWidth: Float, buttonHeight: Float) {
|
|
48
58
|
var yOffset = separatorWidth
|
|
49
|
-
for ((
|
|
59
|
+
for ((rowIndex, row) in keys.withIndex()) {
|
|
50
60
|
var xOffset = separatorWidth
|
|
51
|
-
for ((
|
|
61
|
+
for ((colIndex, key) in row.withIndex()) {
|
|
62
|
+
val isCustomKey = rowIndex == 2 && colIndex == 4
|
|
52
63
|
val width = if (key == "000") buttonWidth * 2 + separatorWidth else buttonWidth
|
|
53
|
-
val height = if (
|
|
64
|
+
val height = if (isCustomKey) buttonHeight * 2 + separatorWidth else buttonHeight
|
|
54
65
|
|
|
55
66
|
val button = if (key == "back") {
|
|
56
67
|
createImageButton(key, xOffset, yOffset, buttonWidth.toInt(), buttonHeight.toInt())
|
|
57
68
|
} else {
|
|
58
|
-
createButton(key, xOffset, yOffset, width.toInt(), height.toInt())
|
|
69
|
+
createButton(key, xOffset, yOffset, width.toInt(), height.toInt(), isCustomKey).also { b ->
|
|
70
|
+
if (isCustomKey) customKeyButton = b
|
|
71
|
+
}
|
|
59
72
|
}
|
|
60
73
|
|
|
61
74
|
addView(button)
|
|
@@ -72,8 +85,8 @@ class CustomKeyboardView(
|
|
|
72
85
|
yOffset: Float,
|
|
73
86
|
buttonWidth: Int,
|
|
74
87
|
buttonHeight: Int,
|
|
88
|
+
isCustomKey: Boolean
|
|
75
89
|
): Button {
|
|
76
|
-
val specialKeys = listOf("=", "-", "×", "÷", "AC", "back", "+")
|
|
77
90
|
return Button(context).apply {
|
|
78
91
|
val shapeInit = GradientDrawable().apply {
|
|
79
92
|
shape = GradientDrawable.RECTANGLE
|
|
@@ -85,9 +98,11 @@ class CustomKeyboardView(
|
|
|
85
98
|
background = shapeInit
|
|
86
99
|
text = key
|
|
87
100
|
setTypeface(typeface)
|
|
88
|
-
textSize = 24.toFloat()
|
|
101
|
+
textSize = (if (isCustomKey) 18 else 24).toFloat()
|
|
89
102
|
setTextColor(Color.BLACK)
|
|
90
103
|
stateListAnimator = null
|
|
104
|
+
maxLines = 1
|
|
105
|
+
isAllCaps = false
|
|
91
106
|
layoutParams = LayoutParams(
|
|
92
107
|
buttonWidth,
|
|
93
108
|
buttonHeight
|
|
@@ -104,10 +119,13 @@ class CustomKeyboardView(
|
|
|
104
119
|
setTextColor(Color.BLACK)
|
|
105
120
|
}
|
|
106
121
|
|
|
122
|
+
isClickable = true
|
|
123
|
+
isFocusable = false
|
|
124
|
+
isFocusableInTouchMode = false
|
|
107
125
|
|
|
108
126
|
translationX = xOffset.toInt().toFloat()
|
|
109
127
|
translationY = yOffset.toInt().toFloat()
|
|
110
|
-
setOnClickListener { onKeyPress(key) }
|
|
128
|
+
setOnClickListener { onKeyPress(key, isCustomKey) }
|
|
111
129
|
}
|
|
112
130
|
}
|
|
113
131
|
|
|
@@ -132,11 +150,16 @@ class CustomKeyboardView(
|
|
|
132
150
|
).apply {
|
|
133
151
|
constrainedWidth = false
|
|
134
152
|
}
|
|
153
|
+
|
|
154
|
+
isClickable = true
|
|
155
|
+
isFocusable = false
|
|
156
|
+
isFocusableInTouchMode = false
|
|
157
|
+
|
|
135
158
|
translationX = xOffset
|
|
136
159
|
translationY = yOffset
|
|
137
160
|
setImageResource(android.R.drawable.ic_input_delete)
|
|
138
161
|
setImageTintList(ColorStateList.valueOf(Color.BLACK))
|
|
139
|
-
setOnClickListener { onKeyPress(key) }
|
|
162
|
+
setOnClickListener { onKeyPress(key, false) }
|
|
140
163
|
}
|
|
141
164
|
}
|
|
142
165
|
|
|
@@ -172,25 +195,18 @@ class CustomKeyboardView(
|
|
|
172
195
|
}
|
|
173
196
|
}
|
|
174
197
|
|
|
175
|
-
private fun onKeyPress(key: String) {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
"back" -> {
|
|
182
|
-
onBackSpace()
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
"=" -> {
|
|
186
|
-
calculateResult()
|
|
187
|
-
}
|
|
198
|
+
private fun onKeyPress(key: String, isCustomKey: Boolean) {
|
|
199
|
+
if (isCustomKey) {
|
|
200
|
+
emitCustomKey()
|
|
201
|
+
return
|
|
202
|
+
}
|
|
188
203
|
|
|
204
|
+
emitKeyPress(key)
|
|
205
|
+
when (key) {
|
|
206
|
+
"back" -> onBackSpace()
|
|
207
|
+
"=" -> calculateResult()
|
|
189
208
|
"×", "+", "-", "÷" -> keyDidPress(" $key ")
|
|
190
|
-
|
|
191
|
-
else -> {
|
|
192
|
-
editText.text?.insert(editText.selectionStart, key)
|
|
193
|
-
}
|
|
209
|
+
else -> editText.text?.insert(editText.selectionStart, key)
|
|
194
210
|
}
|
|
195
211
|
}
|
|
196
212
|
|
|
@@ -199,10 +215,6 @@ class CustomKeyboardView(
|
|
|
199
215
|
editText.text?.replace(editText.selectionStart, editText.selectionEnd, key)
|
|
200
216
|
}
|
|
201
217
|
|
|
202
|
-
private fun clearText() {
|
|
203
|
-
editText.text?.clear()
|
|
204
|
-
}
|
|
205
|
-
|
|
206
218
|
private fun onBackSpace() {
|
|
207
219
|
val start = editText.selectionStart
|
|
208
220
|
val end = editText.selectionEnd
|
|
@@ -239,4 +251,51 @@ class CustomKeyboardView(
|
|
|
239
251
|
}
|
|
240
252
|
}
|
|
241
253
|
|
|
254
|
+
private fun emitKeyPress(key: String) {
|
|
255
|
+
val reactContext = context as ThemedReactContext
|
|
256
|
+
val params = Arguments.createMap().apply {
|
|
257
|
+
putString("key", key)
|
|
258
|
+
}
|
|
259
|
+
reactContext.getJSModule(RCTEventEmitter::class.java)
|
|
260
|
+
.receiveEvent(editText.id, "onKeyPress", params)
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
private fun emitCustomKey() {
|
|
264
|
+
val reactContext = context as ThemedReactContext
|
|
265
|
+
reactContext.getJSModule(RCTEventEmitter::class.java)
|
|
266
|
+
.receiveEvent(editText.id, "onCustomKeyEvent", null)
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
fun setCustomKeyText(text: String) {
|
|
270
|
+
customKeyButton?.text = text
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
fun setCustomKeyBackground(background: Int) {
|
|
274
|
+
customKeyButtonBackground = background
|
|
275
|
+
updateCustomKeyUI(background, customKeyButtonTextColor, customKeyButtonState)
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
fun setCustomKeyTextColor(textColor: Int) {
|
|
279
|
+
customKeyButtonTextColor = textColor
|
|
280
|
+
updateCustomKeyUI(customKeyButtonBackground, textColor, customKeyButtonState)
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
fun setCustomKeyState(state: String) {
|
|
285
|
+
customKeyButtonState = state
|
|
286
|
+
customKeyButton?.isEnabled = state != "disable"
|
|
287
|
+
updateCustomKeyUI(customKeyButtonBackground, customKeyButtonTextColor, state)
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
private fun updateCustomKeyUI(background: Int, textColor: Int, state: String){
|
|
291
|
+
|
|
292
|
+
customKeyButton?.background = GradientDrawable().apply {
|
|
293
|
+
shape = GradientDrawable.RECTANGLE
|
|
294
|
+
cornerRadius = 24f
|
|
295
|
+
setColor(background)
|
|
296
|
+
}
|
|
297
|
+
customKeyButton?.setTextColor(textColor)
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
|
|
242
301
|
}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
package com.calculatorkeyboard
|
|
2
|
+
|
|
3
|
+
import android.annotation.SuppressLint
|
|
4
|
+
import android.app.Activity
|
|
5
|
+
import android.content.Context
|
|
6
|
+
import android.content.ContextWrapper
|
|
7
|
+
import android.util.Log
|
|
8
|
+
import android.view.Gravity
|
|
9
|
+
import android.view.MotionEvent
|
|
10
|
+
import android.view.View
|
|
11
|
+
import android.view.ViewGroup
|
|
12
|
+
import android.widget.FrameLayout
|
|
13
|
+
import androidx.core.view.ViewCompat
|
|
14
|
+
import androidx.core.view.WindowInsetsCompat
|
|
15
|
+
import androidx.core.view.doOnLayout
|
|
16
|
+
import androidx.core.view.updatePadding
|
|
17
|
+
import java.lang.ref.WeakReference
|
|
18
|
+
import androidx.core.view.isNotEmpty
|
|
19
|
+
|
|
20
|
+
internal class KeyboardOverlayHost {
|
|
21
|
+
|
|
22
|
+
private val tag = "KeyboardOverlayHost"
|
|
23
|
+
|
|
24
|
+
private var localRootRef: WeakReference<ViewGroup>? = null
|
|
25
|
+
private var containerRef: WeakReference<FrameLayout>? = null
|
|
26
|
+
private var paddingTargetRef: WeakReference<View>? = null
|
|
27
|
+
|
|
28
|
+
private var originalBottomPadding: Int = 0
|
|
29
|
+
private var isShowing = false
|
|
30
|
+
|
|
31
|
+
private class OverlayContainer(ctx: Context) : FrameLayout(ctx) {
|
|
32
|
+
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean = false
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
fun show(anchorView: View, keyboardView: View, heightPx: Int) {
|
|
36
|
+
val localRoot = findLocalRoot(anchorView) ?: run {
|
|
37
|
+
Log.w(tag, "show: cannot find local root from anchorView")
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
val container = ensureContainer(localRoot, anchorView.context) ?: return
|
|
41
|
+
|
|
42
|
+
val paddingTarget = findPaddingTargetWithin(anchorView, localRoot)
|
|
43
|
+
paddingTargetRef = WeakReference(paddingTarget)
|
|
44
|
+
localRootRef = WeakReference(localRoot)
|
|
45
|
+
|
|
46
|
+
val bottomInset = (ViewCompat.getRootWindowInsets(container)
|
|
47
|
+
?.getInsets(WindowInsetsCompat.Type.systemBars())?.bottom) ?: 0
|
|
48
|
+
|
|
49
|
+
val lp = FrameLayout.LayoutParams(
|
|
50
|
+
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
51
|
+
heightPx + bottomInset
|
|
52
|
+
).apply { gravity = Gravity.BOTTOM }
|
|
53
|
+
|
|
54
|
+
if (keyboardView.parent !== container) {
|
|
55
|
+
container.removeAllViews()
|
|
56
|
+
container.addView(keyboardView, lp)
|
|
57
|
+
} else {
|
|
58
|
+
keyboardView.layoutParams = lp
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
keyboardView.isClickable = true
|
|
62
|
+
keyboardView.isFocusable = false
|
|
63
|
+
keyboardView.isFocusableInTouchMode = false
|
|
64
|
+
keyboardView.visibility = View.VISIBLE
|
|
65
|
+
|
|
66
|
+
if (!isShowing) originalBottomPadding = paddingTarget.paddingBottom
|
|
67
|
+
paddingTarget.updatePadding(bottom = heightPx)
|
|
68
|
+
|
|
69
|
+
container.visibility = View.VISIBLE
|
|
70
|
+
container.bringToFront()
|
|
71
|
+
container.translationZ = 10000f
|
|
72
|
+
container.elevation = 10000f
|
|
73
|
+
localRoot.post { container.bringToFront() }
|
|
74
|
+
|
|
75
|
+
keyboardView.animate().cancel()
|
|
76
|
+
keyboardView.post {
|
|
77
|
+
container.bringToFront()
|
|
78
|
+
keyboardView.doOnLayout { child ->
|
|
79
|
+
val h = child.height.takeIf { it > 0 } ?: heightPx
|
|
80
|
+
child.translationY = h.toFloat()
|
|
81
|
+
child.animate()
|
|
82
|
+
.translationY(0f)
|
|
83
|
+
.setDuration(250L)
|
|
84
|
+
.withStartAction {
|
|
85
|
+
isShowing = true
|
|
86
|
+
child.setLayerType(View.LAYER_TYPE_HARDWARE, null)
|
|
87
|
+
container.bringToFront()
|
|
88
|
+
}
|
|
89
|
+
.withEndAction {
|
|
90
|
+
child.setLayerType(View.LAYER_TYPE_NONE, null)
|
|
91
|
+
}
|
|
92
|
+
.start()
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
fun hide() {
|
|
98
|
+
val container = containerRef?.get() ?: return
|
|
99
|
+
val localRoot = localRootRef?.get() ?: return
|
|
100
|
+
val paddingTarget = paddingTargetRef?.get() ?: localRoot
|
|
101
|
+
|
|
102
|
+
val child = if (container.isNotEmpty())
|
|
103
|
+
container.getChildAt(container.childCount - 1) else null
|
|
104
|
+
|
|
105
|
+
if (child == null) {
|
|
106
|
+
paddingTarget.updatePadding(bottom = originalBottomPadding)
|
|
107
|
+
isShowing = false
|
|
108
|
+
return
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
child.animate().cancel()
|
|
112
|
+
val h = child.height.takeIf { it > 0 } ?: (child.measuredHeight.takeIf { it > 0 } ?: 0)
|
|
113
|
+
if (h == 0) {
|
|
114
|
+
container.removeAllViews()
|
|
115
|
+
paddingTarget.updatePadding(bottom = originalBottomPadding)
|
|
116
|
+
isShowing = false
|
|
117
|
+
return
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
child.animate()
|
|
121
|
+
.translationY(h.toFloat())
|
|
122
|
+
.setDuration(250L)
|
|
123
|
+
.withEndAction {
|
|
124
|
+
container.removeAllViews()
|
|
125
|
+
paddingTarget.updatePadding(bottom = originalBottomPadding)
|
|
126
|
+
isShowing = false
|
|
127
|
+
}
|
|
128
|
+
.start()
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
fun detach() {
|
|
132
|
+
containerRef?.get()?.let { (it.parent as? ViewGroup)?.removeView(it) }
|
|
133
|
+
containerRef = null
|
|
134
|
+
localRootRef = null
|
|
135
|
+
paddingTargetRef = null
|
|
136
|
+
isShowing = false
|
|
137
|
+
originalBottomPadding = 0
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
private fun findLocalRoot(anchor: View): ViewGroup? {
|
|
141
|
+
var cur: View? = anchor
|
|
142
|
+
|
|
143
|
+
while (cur != null) {
|
|
144
|
+
if (cur is ViewGroup && isReactRoot(cur)) {
|
|
145
|
+
return cur
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
val parent = cur.parent
|
|
149
|
+
if (parent is ViewGroup) {
|
|
150
|
+
val parentName = parent::class.java.simpleName
|
|
151
|
+
if (parentName.contains("FragmentContainerView")) {
|
|
152
|
+
return (cur as? ViewGroup) ?: parent
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
cur = (cur.parent as? View)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return (anchor.rootView as? ViewGroup)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
private fun isReactRoot(v: View): Boolean {
|
|
163
|
+
val n = v::class.java.simpleName
|
|
164
|
+
return n.contains("ReactRootView") ||
|
|
165
|
+
n.contains("RNGestureHandlerEnabledRootView") ||
|
|
166
|
+
(n.contains("React") && n.contains("Root"))
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
@SuppressLint("ClickableViewAccessibility")
|
|
170
|
+
private fun ensureContainer(localRoot: ViewGroup, ctx: Context): FrameLayout? {
|
|
171
|
+
var container = containerRef?.get()
|
|
172
|
+
|
|
173
|
+
if (container == null || container.parent !== localRoot) {
|
|
174
|
+
container?.let { (it.parent as? ViewGroup)?.removeView(it) }
|
|
175
|
+
|
|
176
|
+
container = OverlayContainer(ctx).apply {
|
|
177
|
+
layoutParams = ViewGroup.LayoutParams(
|
|
178
|
+
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
179
|
+
ViewGroup.LayoutParams.MATCH_PARENT
|
|
180
|
+
)
|
|
181
|
+
isClickable = false
|
|
182
|
+
isFocusable = false
|
|
183
|
+
elevation = 10000f
|
|
184
|
+
translationZ = 10000f
|
|
185
|
+
visibility = View.VISIBLE
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
localRoot.addView(container)
|
|
189
|
+
container.bringToFront()
|
|
190
|
+
localRoot.requestLayout()
|
|
191
|
+
containerRef = WeakReference(container)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return container
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
private fun findPaddingTargetWithin(anchor: View, localRoot: ViewGroup): View {
|
|
198
|
+
fun dfs(g: ViewGroup): View? {
|
|
199
|
+
if (isReactRoot(g)) return g
|
|
200
|
+
for (i in 0 until g.childCount) {
|
|
201
|
+
val c = g.getChildAt(i)
|
|
202
|
+
if (c is ViewGroup) {
|
|
203
|
+
val hit = dfs(c)
|
|
204
|
+
if (hit != null) return hit
|
|
205
|
+
} else if (isReactRoot(c)) {
|
|
206
|
+
return c
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return null
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
dfs(localRoot)?.let { return it }
|
|
213
|
+
|
|
214
|
+
var cur: View? = anchor
|
|
215
|
+
var last: View = anchor
|
|
216
|
+
while (cur != null && cur !== localRoot) {
|
|
217
|
+
last = cur
|
|
218
|
+
cur = (cur.parent as? View)
|
|
219
|
+
}
|
|
220
|
+
return last as? ViewGroup ?: localRoot
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
@Suppress("unused")
|
|
224
|
+
private fun findActivityFrom(view: View): Activity? {
|
|
225
|
+
var ctx: Context? = view.context
|
|
226
|
+
while (ctx is ContextWrapper) {
|
|
227
|
+
if (ctx is Activity) return ctx
|
|
228
|
+
ctx = ctx.baseContext
|
|
229
|
+
}
|
|
230
|
+
return null
|
|
231
|
+
}
|
|
232
|
+
}
|
|
@@ -1,41 +1,37 @@
|
|
|
1
1
|
package com.calculatorkeyboard
|
|
2
2
|
|
|
3
3
|
import android.annotation.SuppressLint
|
|
4
|
-
import android.
|
|
5
|
-
import android.graphics.
|
|
6
|
-
import android.graphics.drawable.ColorDrawable
|
|
7
|
-
import android.view.Gravity
|
|
4
|
+
import android.content.Context
|
|
5
|
+
import android.graphics.Color
|
|
8
6
|
import android.view.KeyEvent
|
|
9
|
-
import android.view.
|
|
10
|
-
import android.view.WindowInsets
|
|
11
|
-
import android.view.WindowManager
|
|
12
|
-
import android.widget.PopupWindow
|
|
13
|
-
import androidx.constraintlayout.widget.ConstraintLayout
|
|
7
|
+
import android.view.inputmethod.InputMethodManager
|
|
14
8
|
import androidx.core.graphics.toColorInt
|
|
9
|
+
import androidx.core.view.ViewCompat
|
|
10
|
+
import androidx.core.view.WindowInsetsCompat
|
|
15
11
|
import com.facebook.react.bridge.ReadableArray
|
|
16
12
|
import com.facebook.react.bridge.UiThreadUtil
|
|
13
|
+
import com.facebook.react.uimanager.PixelUtil.dpToPx
|
|
17
14
|
import com.facebook.react.uimanager.ThemedReactContext
|
|
18
15
|
import com.facebook.react.uimanager.annotations.ReactProp
|
|
19
16
|
import com.facebook.react.views.textinput.ReactEditText
|
|
20
17
|
import com.facebook.react.views.textinput.ReactTextInputManager
|
|
21
|
-
import androidx.core.graphics.drawable.toDrawable
|
|
22
|
-
import androidx.core.view.ViewCompat
|
|
23
|
-
import androidx.core.view.WindowInsetsCompat
|
|
24
|
-
import com.facebook.react.uimanager.PixelUtil.dpToPx
|
|
25
18
|
|
|
26
19
|
class RCTInputCalculator : ReactTextInputManager() {
|
|
27
20
|
|
|
28
21
|
private var keyboardView: CustomKeyboardView? = null
|
|
29
|
-
private var calculatorHeight: Int = 290.dpToPx().toInt()
|
|
30
|
-
private var popup: PopupWindow? = null
|
|
31
|
-
private val animationDuration = 250L
|
|
32
|
-
|
|
33
22
|
private lateinit var editText: CalculatorEditText
|
|
23
|
+
private lateinit var imm: InputMethodManager
|
|
24
|
+
|
|
25
|
+
private val overlayHost = KeyboardOverlayHost()
|
|
26
|
+
|
|
27
|
+
private var backListenerAttached = false
|
|
28
|
+
private var overlayShowing = false
|
|
34
29
|
|
|
35
30
|
override fun getName() = REACT_CLASS
|
|
36
31
|
|
|
37
32
|
companion object {
|
|
38
33
|
const val REACT_CLASS = "RCTInputCalculator"
|
|
34
|
+
val calculatorHeight: Int = 240.dpToPx().toInt()
|
|
39
35
|
}
|
|
40
36
|
|
|
41
37
|
@ReactProp(name = "value")
|
|
@@ -47,15 +43,31 @@ class RCTInputCalculator : ReactTextInputManager() {
|
|
|
47
43
|
|
|
48
44
|
val wasFocused = view.hasFocus()
|
|
49
45
|
val atEnd = wasFocused && view.selectionStart == e.length && view.selectionEnd == e.length
|
|
50
|
-
|
|
51
46
|
e.replace(0, e.length, newText)
|
|
52
|
-
|
|
53
|
-
if (!wasFocused || atEnd) {
|
|
54
|
-
view.setSelection(newText.length)
|
|
55
|
-
}
|
|
47
|
+
if (!wasFocused || atEnd) view.setSelection(newText.length)
|
|
56
48
|
}
|
|
57
49
|
}
|
|
58
50
|
|
|
51
|
+
@ReactProp(name = "customKeyText")
|
|
52
|
+
fun setCustomKeyText(view: ReactEditText, text: String?) {
|
|
53
|
+
keyboardView?.setCustomKeyText(text ?: "Xong")
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
@ReactProp(name = "customKeyBackground")
|
|
57
|
+
fun setCustomKeyBackground(view: ReactEditText, background: String?) {
|
|
58
|
+
keyboardView?.setCustomKeyBackground((background ?: "#d8d8d8").toColorInt())
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@ReactProp(name = "customKeyTextColor")
|
|
62
|
+
fun setCustomKeyTextColor(view: ReactEditText, textColor: String?) {
|
|
63
|
+
keyboardView?.setCustomKeyTextColor(textColor?.toColorInt() ?: Color.BLACK)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
@ReactProp(name = "customKeyState")
|
|
67
|
+
fun setCustomKeyState(view: ReactEditText, state: String?) {
|
|
68
|
+
keyboardView?.setCustomKeyState(state ?: "default")
|
|
69
|
+
}
|
|
70
|
+
|
|
59
71
|
@ReactProp(name = "keyboardColor")
|
|
60
72
|
fun setKeyboardColor(view: ReactEditText, color: String) {
|
|
61
73
|
keyboardView?.updateButtonColors(color.toColorInt())
|
|
@@ -63,8 +75,32 @@ class RCTInputCalculator : ReactTextInputManager() {
|
|
|
63
75
|
|
|
64
76
|
@SuppressLint("ClickableViewAccessibility")
|
|
65
77
|
override fun createViewInstance(context: ThemedReactContext): ReactEditText {
|
|
78
|
+
imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
|
79
|
+
|
|
66
80
|
editText = CalculatorEditText(context).apply {
|
|
67
81
|
showSoftInputOnFocus = false
|
|
82
|
+
isFocusableInTouchMode = true
|
|
83
|
+
setOnTouchListener { v, event ->
|
|
84
|
+
if (event.action == android.view.MotionEvent.ACTION_DOWN) {
|
|
85
|
+
showSoftInputOnFocus = false
|
|
86
|
+
ViewCompat.getWindowInsetsController(this)?.hide(WindowInsetsCompat.Type.ime())
|
|
87
|
+
imm.hideSoftInputFromWindow(windowToken, 0)
|
|
88
|
+
|
|
89
|
+
if (!isFocused) requestFocus()
|
|
90
|
+
|
|
91
|
+
val kb = keyboardView
|
|
92
|
+
if (kb != null && !overlayShowing) {
|
|
93
|
+
overlayHost.show(
|
|
94
|
+
anchorView = this,
|
|
95
|
+
keyboardView = kb,
|
|
96
|
+
heightPx = calculatorHeight
|
|
97
|
+
)
|
|
98
|
+
overlayShowing = true
|
|
99
|
+
}
|
|
100
|
+
return@setOnTouchListener true
|
|
101
|
+
}
|
|
102
|
+
false
|
|
103
|
+
}
|
|
68
104
|
}
|
|
69
105
|
|
|
70
106
|
keyboardView = CustomKeyboardView(context, editText).apply {
|
|
@@ -72,19 +108,34 @@ class RCTInputCalculator : ReactTextInputManager() {
|
|
|
72
108
|
elevation = 24f
|
|
73
109
|
}
|
|
74
110
|
|
|
111
|
+
if (!backListenerAttached) {
|
|
112
|
+
editText.setOnKeyListener { v, keyCode, event ->
|
|
113
|
+
if (keyCode == KeyEvent.KEYCODE_BACK && event.action == KeyEvent.ACTION_UP && v.hasFocus()) {
|
|
114
|
+
v.clearFocus()
|
|
115
|
+
true
|
|
116
|
+
} else false
|
|
117
|
+
}
|
|
118
|
+
backListenerAttached = true
|
|
119
|
+
}
|
|
120
|
+
|
|
75
121
|
editText.onFocusListener = object : CalculatorEditText.OnFocusChangeListener {
|
|
76
122
|
override fun onFocusChange(view: CalculatorEditText, hasFocus: Boolean) {
|
|
77
123
|
UiThreadUtil.runOnUiThread {
|
|
78
124
|
if (hasFocus) {
|
|
79
|
-
|
|
125
|
+
disableSystemImeFor(view)
|
|
126
|
+
if (!overlayShowing) {
|
|
127
|
+
val kb = keyboardView ?: return@runOnUiThread
|
|
128
|
+
overlayHost.show(
|
|
129
|
+
anchorView = view,
|
|
130
|
+
keyboardView = kb,
|
|
131
|
+
heightPx = calculatorHeight
|
|
132
|
+
)
|
|
133
|
+
overlayShowing = true
|
|
134
|
+
}
|
|
80
135
|
} else {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
if (keyCode == KeyEvent.KEYCODE_BACK && hasFocus) {
|
|
85
|
-
v.clearFocus()
|
|
86
|
-
true
|
|
87
|
-
} else false
|
|
136
|
+
overlayHost.hide()
|
|
137
|
+
overlayShowing = false
|
|
138
|
+
enableSystemImeFor(view)
|
|
88
139
|
}
|
|
89
140
|
}
|
|
90
141
|
}
|
|
@@ -93,87 +144,54 @@ class RCTInputCalculator : ReactTextInputManager() {
|
|
|
93
144
|
return editText
|
|
94
145
|
}
|
|
95
146
|
|
|
96
|
-
override fun getCommandsMap(): Map<String, Int> {
|
|
97
|
-
return mapOf(
|
|
98
|
-
"blur" to 1,
|
|
99
|
-
"focus" to 2
|
|
100
|
-
)
|
|
101
|
-
}
|
|
102
147
|
|
|
103
|
-
override fun
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
148
|
+
override fun onDropViewInstance(view: ReactEditText) {
|
|
149
|
+
super.onDropViewInstance(view)
|
|
150
|
+
overlayHost.hide()
|
|
151
|
+
overlayHost.detach()
|
|
152
|
+
overlayShowing = false
|
|
153
|
+
|
|
108
154
|
}
|
|
109
155
|
|
|
110
|
-
private fun
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
popup = PopupWindow(
|
|
115
|
-
content,
|
|
116
|
-
WindowManager.LayoutParams.MATCH_PARENT,
|
|
117
|
-
calculatorHeight + bottomInsetFrom(editText.rootView),
|
|
118
|
-
false
|
|
119
|
-
).apply {
|
|
120
|
-
setBackgroundDrawable(android.graphics.Color.TRANSPARENT.toDrawable())
|
|
121
|
-
isOutsideTouchable = false
|
|
122
|
-
isClippingEnabled = false
|
|
123
|
-
softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING
|
|
124
|
-
inputMethodMode = PopupWindow.INPUT_METHOD_NOT_NEEDED
|
|
156
|
+
private fun disableSystemImeFor(v: ReactEditText) {
|
|
157
|
+
v.showSoftInputOnFocus = false
|
|
158
|
+
if (android.os.Build.VERSION.SDK_INT >= 30) {
|
|
159
|
+
ViewCompat.getWindowInsetsController(v)?.hide(WindowInsetsCompat.Type.ime())
|
|
125
160
|
}
|
|
161
|
+
imm.hideSoftInputFromWindow(v.windowToken, 0)
|
|
126
162
|
}
|
|
127
163
|
|
|
128
|
-
private fun
|
|
129
|
-
|
|
130
|
-
val mask = WindowInsetsCompat.Type.navigationBars() or WindowInsetsCompat.Type.displayCutout()
|
|
131
|
-
return insets.getInsets(mask).bottom
|
|
164
|
+
private fun enableSystemImeFor(v: ReactEditText) {
|
|
165
|
+
v.showSoftInputOnFocus = true
|
|
132
166
|
}
|
|
133
167
|
|
|
134
|
-
|
|
135
|
-
ensurePopup()
|
|
136
|
-
val p = popup ?: return
|
|
137
|
-
if (p.isShowing) return
|
|
168
|
+
override fun getCommandsMap(): Map<String, Int> = mapOf("blur" to 1, "focus" to 2)
|
|
138
169
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
root.animate()
|
|
145
|
-
?.translationY(0f)
|
|
146
|
-
?.setDuration(animationDuration)
|
|
147
|
-
?.start()
|
|
170
|
+
override fun receiveCommand(reactEditText: ReactEditText, commandId: Int, args: ReadableArray?) {
|
|
171
|
+
when (commandId) {
|
|
172
|
+
1 -> blur()
|
|
173
|
+
2 -> focus()
|
|
174
|
+
}
|
|
148
175
|
}
|
|
149
176
|
|
|
150
|
-
|
|
151
|
-
val
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
root.animate()
|
|
156
|
-
.translationY(calculatorHeight.toFloat())
|
|
157
|
-
.setDuration(animationDuration)
|
|
158
|
-
.withEndAction {
|
|
159
|
-
try {
|
|
160
|
-
if (p.isShowing) p.dismiss()
|
|
161
|
-
} catch (_: Throwable) { }
|
|
162
|
-
}
|
|
163
|
-
.start()
|
|
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
|
|
181
|
+
}
|
|
164
182
|
|
|
165
|
-
|
|
183
|
+
override fun getExportedCustomDirectEventTypeConstants(): MutableMap<String, Any> {
|
|
184
|
+
val base = super.getExportedCustomDirectEventTypeConstants().toMutableMap()
|
|
185
|
+
base["onCustomKeyEvent"] = mapOf("registrationName" to "onCustomKeyEvent")
|
|
186
|
+
return base
|
|
166
187
|
}
|
|
167
188
|
|
|
168
189
|
private fun focus() {
|
|
169
|
-
UiThreadUtil.runOnUiThread {
|
|
170
|
-
if (!editText.isFocused) editText.requestFocus()
|
|
171
|
-
}
|
|
190
|
+
UiThreadUtil.runOnUiThread { if (!editText.isFocused) editText.requestFocus() }
|
|
172
191
|
}
|
|
173
192
|
|
|
174
193
|
private fun blur() {
|
|
175
|
-
UiThreadUtil.runOnUiThread {
|
|
176
|
-
if (editText.isFocused) editText.clearFocus()
|
|
177
|
-
}
|
|
194
|
+
UiThreadUtil.runOnUiThread { if (editText.isFocused) editText.clearFocus() }
|
|
178
195
|
}
|
|
179
196
|
}
|
|
197
|
+
|
|
@@ -8,14 +8,20 @@ class CalculatorKeyboardView: UIView {
|
|
|
8
8
|
weak var input: InputCalculator?
|
|
9
9
|
|
|
10
10
|
private let keys: [[String]] = [
|
|
11
|
-
["
|
|
12
|
-
["
|
|
13
|
-
["
|
|
14
|
-
["
|
|
15
|
-
["000", "0"]
|
|
11
|
+
["1", "2", "3", "÷", "back"],
|
|
12
|
+
["4", "5", "6", "×", "="],
|
|
13
|
+
["7", "8", "9", "-", "Xong"],
|
|
14
|
+
["000", "0", "+"],
|
|
16
15
|
]
|
|
17
16
|
private let SEPARATOR_WIDTH: CGFloat = 4
|
|
18
|
-
private let specialKeys: Set<String> = ["=", "-", "×", "÷", "
|
|
17
|
+
private let specialKeys: Set<String> = ["=", "-", "×", "÷", "back", "+"]
|
|
18
|
+
|
|
19
|
+
var customKeyText: String? { didSet { updateCustomKeyTitle() } }
|
|
20
|
+
var customKeyBackground: String? { didSet { updateCustomKeyBackground() } }
|
|
21
|
+
var customKeyTextColor: String? { didSet { updateCustomKeyBackground() } }
|
|
22
|
+
var customKeyState: String? { didSet { updateCustomKeyBackground() } }
|
|
23
|
+
private weak var customKeyButton: UIButton?
|
|
24
|
+
|
|
19
25
|
|
|
20
26
|
override init(frame: CGRect) {
|
|
21
27
|
super.init(frame: frame)
|
|
@@ -34,8 +40,8 @@ class CalculatorKeyboardView: UIView {
|
|
|
34
40
|
self.subviews.forEach { $0.removeFromSuperview() }
|
|
35
41
|
|
|
36
42
|
backgroundColor = UIColor(hex: "#f2f2f6")
|
|
37
|
-
let buttonWidth = (UIScreen.main.bounds.width - SEPARATOR_WIDTH * 2 -
|
|
38
|
-
let buttonHeight: CGFloat = (
|
|
43
|
+
let buttonWidth = (UIScreen.main.bounds.width - SEPARATOR_WIDTH * 2 - 4 * SEPARATOR_WIDTH) / 5
|
|
44
|
+
let buttonHeight: CGFloat = (240 - SEPARATOR_WIDTH * 2 - 3 * SEPARATOR_WIDTH) / 4
|
|
39
45
|
|
|
40
46
|
// Create a wrapper view
|
|
41
47
|
let contentView = UIView()
|
|
@@ -52,19 +58,22 @@ class CalculatorKeyboardView: UIView {
|
|
|
52
58
|
|
|
53
59
|
// Add buttons to the wrapper view
|
|
54
60
|
var yOffset: CGFloat = 0
|
|
55
|
-
for row in keys {
|
|
61
|
+
for (rowIndex, row) in keys.enumerated() {
|
|
56
62
|
var xOffset: CGFloat = 0
|
|
57
|
-
for key in row {
|
|
63
|
+
for (colIndex, key) in row.enumerated() {
|
|
64
|
+
let isCustomKey = colIndex == 4 && rowIndex == 2
|
|
58
65
|
let button = UIButton(type: .system)
|
|
59
66
|
button.backgroundColor = UIColor.white
|
|
60
67
|
button.layer.cornerRadius = 8
|
|
61
|
-
|
|
68
|
+
let title = isCustomKey ? (customKeyText ?? key) : key
|
|
69
|
+
button.setTitle(title, for: .normal)
|
|
62
70
|
button.setTitleColor(.black, for: .normal)
|
|
63
|
-
button.titleLabel?.font = UIFont.systemFont(ofSize: 24, weight: .medium)
|
|
71
|
+
button.titleLabel?.font = UIFont.systemFont(ofSize: isCustomKey ? 18 : 24, weight: .medium)
|
|
64
72
|
button.nativeID = key
|
|
73
|
+
button.tag = isCustomKey ? 1 : 0
|
|
65
74
|
|
|
66
75
|
var buttonFrame = CGRect(x: xOffset, y: yOffset, width: buttonWidth, height: buttonHeight)
|
|
67
|
-
if
|
|
76
|
+
if isCustomKey {
|
|
68
77
|
buttonFrame.size.height = buttonHeight * 2 + SEPARATOR_WIDTH
|
|
69
78
|
}
|
|
70
79
|
if key == "000" {
|
|
@@ -85,6 +94,10 @@ class CalculatorKeyboardView: UIView {
|
|
|
85
94
|
button.backgroundColor = color
|
|
86
95
|
}
|
|
87
96
|
|
|
97
|
+
if isCustomKey {
|
|
98
|
+
self.customKeyButton = button
|
|
99
|
+
}
|
|
100
|
+
|
|
88
101
|
button.addTarget(self, action: #selector(keyPressed(_:)), for: .touchUpInside)
|
|
89
102
|
contentView.addSubview(button)
|
|
90
103
|
|
|
@@ -96,12 +109,37 @@ class CalculatorKeyboardView: UIView {
|
|
|
96
109
|
}
|
|
97
110
|
}
|
|
98
111
|
|
|
112
|
+
private func updateCustomKeyTitle() {
|
|
113
|
+
guard let btn = customKeyButton, let title = customKeyText else { return }
|
|
114
|
+
btn.setTitle(title, for: .normal)
|
|
115
|
+
btn.setImage(nil, for: .normal)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
private func updateCustomKeyBackground() {
|
|
119
|
+
guard let btn = customKeyButton,
|
|
120
|
+
let background = customKeyBackground,
|
|
121
|
+
let textColor = customKeyTextColor,
|
|
122
|
+
let state = customKeyState else { return }
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
btn.isEnabled = state != "disable"
|
|
127
|
+
btn.backgroundColor = UIColor(hex: background)
|
|
128
|
+
btn.setTitleColor(UIColor(hex: textColor), for: .normal)
|
|
129
|
+
|
|
130
|
+
}
|
|
131
|
+
|
|
99
132
|
|
|
100
133
|
@objc private func keyPressed(_ sender: UIButton) {
|
|
101
134
|
guard let key = sender.nativeID else { return }
|
|
135
|
+
let isCustomKey = sender.tag == 1
|
|
136
|
+
if (isCustomKey) {
|
|
137
|
+
input?.emitCustomKey()
|
|
138
|
+
return
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
input?.emitKeyPress(key)
|
|
102
142
|
switch key {
|
|
103
|
-
case "AC":
|
|
104
|
-
input?.clearText()
|
|
105
143
|
case "back":
|
|
106
144
|
input?.onBackSpace()
|
|
107
145
|
case "=":
|
package/ios/InputCalculator.m
CHANGED
|
@@ -56,6 +56,8 @@ RCT_EXPORT_SHADOW_PROPERTY(onContentSizeChange, RCTDirectEventBlock)
|
|
|
56
56
|
RCT_EXPORT_VIEW_PROPERTY(value, NSString)
|
|
57
57
|
RCT_EXPORT_VIEW_PROPERTY(onFocus, RCTBubblingEventBlock)
|
|
58
58
|
RCT_EXPORT_VIEW_PROPERTY(onBlur, RCTBubblingEventBlock)
|
|
59
|
+
RCT_EXPORT_VIEW_PROPERTY(onKeyPress, RCTBubblingEventBlock)
|
|
60
|
+
RCT_EXPORT_VIEW_PROPERTY(onCustomKeyEvent, RCTDirectEventBlock)
|
|
59
61
|
|
|
60
62
|
RCT_EXPORT_METHOD(focus : (nonnull NSNumber *)viewTag)
|
|
61
63
|
{
|
|
@@ -74,6 +76,10 @@ RCT_EXPORT_METHOD(blur : (nonnull NSNumber *)viewTag)
|
|
|
74
76
|
}
|
|
75
77
|
|
|
76
78
|
RCT_EXPORT_VIEW_PROPERTY(keyboardColor, UIColor)
|
|
79
|
+
RCT_EXPORT_VIEW_PROPERTY(customKeyText, NSString)
|
|
80
|
+
RCT_EXPORT_VIEW_PROPERTY(customKeyBackground, NSString)
|
|
81
|
+
RCT_EXPORT_VIEW_PROPERTY(customKeyTextColor, NSString)
|
|
82
|
+
RCT_EXPORT_VIEW_PROPERTY(customKeyState, NSString)
|
|
77
83
|
|
|
78
84
|
@end
|
|
79
85
|
|
|
@@ -19,6 +19,24 @@ class InputCalculator: RCTSinglelineTextInputView {
|
|
|
19
19
|
|
|
20
20
|
@objc var onFocus: RCTBubblingEventBlock?
|
|
21
21
|
@objc var onBlur: RCTBubblingEventBlock?
|
|
22
|
+
@objc var onKeyPress: RCTBubblingEventBlock?
|
|
23
|
+
@objc var onCustomKeyEvent: RCTDirectEventBlock?
|
|
24
|
+
|
|
25
|
+
@objc var customKeyText: String? {
|
|
26
|
+
didSet { keyboardView?.customKeyText = customKeyText as String? }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@objc var customKeyBackground: String? {
|
|
30
|
+
didSet { keyboardView?.customKeyBackground = customKeyBackground }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@objc var customKeyTextColor: String? {
|
|
34
|
+
didSet { keyboardView?.customKeyTextColor = customKeyTextColor }
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@objc var customKeyState: String? {
|
|
38
|
+
didSet { keyboardView?.customKeyState = customKeyState }
|
|
39
|
+
}
|
|
22
40
|
|
|
23
41
|
@objc func beginEditingInput(_ note: Notification) { onFocus?([:]) }
|
|
24
42
|
@objc func endEditingInput(_ note: Notification) { onBlur?([:]) }
|
|
@@ -50,7 +68,7 @@ class InputCalculator: RCTSinglelineTextInputView {
|
|
|
50
68
|
super.init(bridge: bridge)
|
|
51
69
|
self.bridge = bridge
|
|
52
70
|
self.keyboardView = CalculatorKeyboardView()
|
|
53
|
-
self.keyboardView!.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height:
|
|
71
|
+
self.keyboardView!.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: 240 + getbottomInset())
|
|
54
72
|
self.keyboardView!.input = self
|
|
55
73
|
|
|
56
74
|
backedTextInputView.inputView = self.keyboardView
|
|
@@ -79,19 +97,12 @@ class InputCalculator: RCTSinglelineTextInputView {
|
|
|
79
97
|
func keyDidPress(_ key: String) {
|
|
80
98
|
backedTextInputView.insertText(key)
|
|
81
99
|
value += key
|
|
100
|
+
|
|
82
101
|
if let bridge = bridge {
|
|
83
102
|
bridge.eventDispatcher().sendTextEvent(with: .change, reactTag: reactTag, text: value, key: "\(key)", eventCount: 1)
|
|
84
103
|
}
|
|
85
104
|
}
|
|
86
105
|
|
|
87
|
-
func clearText() {
|
|
88
|
-
value = ""
|
|
89
|
-
(backedTextInputView as? UITextField)?.text = ""
|
|
90
|
-
if let bridge = bridge {
|
|
91
|
-
bridge.eventDispatcher().sendTextEvent(with: .change, reactTag: reactTag, text: value, key: "clear", eventCount: 1)
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
106
|
func onBackSpace() {
|
|
96
107
|
value = value.dropLast().description
|
|
97
108
|
DispatchQueue.main.async {
|
|
@@ -102,7 +113,7 @@ class InputCalculator: RCTSinglelineTextInputView {
|
|
|
102
113
|
self.backedTextInputView.replace(newRange, withText: "")
|
|
103
114
|
}
|
|
104
115
|
}
|
|
105
|
-
|
|
116
|
+
|
|
106
117
|
if let bridge = bridge {
|
|
107
118
|
bridge.eventDispatcher().sendTextEvent(with: .change, reactTag: reactTag, text: value, key: "back", eventCount: 1)
|
|
108
119
|
}
|
|
@@ -124,6 +135,7 @@ class InputCalculator: RCTSinglelineTextInputView {
|
|
|
124
135
|
if let result = expression.expressionValue(with: nil, context: nil) as? NSNumber {
|
|
125
136
|
textField.text = result.stringValue
|
|
126
137
|
value = result.stringValue
|
|
138
|
+
|
|
127
139
|
if let bridge = bridge {
|
|
128
140
|
bridge.eventDispatcher().sendTextEvent(with: .change, reactTag: reactTag, text: value, key: "=", eventCount: 1)
|
|
129
141
|
}
|
|
@@ -133,6 +145,14 @@ class InputCalculator: RCTSinglelineTextInputView {
|
|
|
133
145
|
print("Invalid expression")
|
|
134
146
|
}
|
|
135
147
|
}
|
|
148
|
+
|
|
149
|
+
func emitCustomKey() {
|
|
150
|
+
onCustomKeyEvent?([:])
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
func emitKeyPress(_ key: String) {
|
|
154
|
+
onKeyPress?(["key": key])
|
|
155
|
+
}
|
|
136
156
|
|
|
137
157
|
}
|
|
138
158
|
|
package/lib/commonjs/index.js
CHANGED
|
@@ -10,7 +10,15 @@ var _jsxRuntime = require("react/jsx-runtime");
|
|
|
10
10
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
11
|
const NAME = 'RCTInputCalculator';
|
|
12
12
|
const NativeInput = (0, _reactNative.requireNativeComponent)(NAME);
|
|
13
|
-
const InputCalculator = /*#__PURE__*/_react.default.forwardRef((
|
|
13
|
+
const InputCalculator = /*#__PURE__*/_react.default.forwardRef(({
|
|
14
|
+
customKeyBackground = 'default',
|
|
15
|
+
keyboardColor = '',
|
|
16
|
+
customKeyText,
|
|
17
|
+
onKeyPress,
|
|
18
|
+
customKeyState = 'default',
|
|
19
|
+
onCustomKeyEvent,
|
|
20
|
+
...props
|
|
21
|
+
}, ref) => {
|
|
14
22
|
const nativeRef = _react.default.useRef(null);
|
|
15
23
|
const _onChange = event => {
|
|
16
24
|
const currentText = event.nativeEvent.text;
|
|
@@ -18,6 +26,16 @@ const InputCalculator = /*#__PURE__*/_react.default.forwardRef((props, ref) => {
|
|
|
18
26
|
props.onChangeText && props.onChangeText(currentText);
|
|
19
27
|
};
|
|
20
28
|
const text = props.text ?? props.defaultValue ?? '';
|
|
29
|
+
let keyBackground = '#D8D8D8';
|
|
30
|
+
let textKeyColor = '#000000';
|
|
31
|
+
if (customKeyBackground === 'primary') {
|
|
32
|
+
keyBackground = '#EB2F96';
|
|
33
|
+
textKeyColor = '#FFFFFF';
|
|
34
|
+
}
|
|
35
|
+
if (customKeyState === 'disable') {
|
|
36
|
+
keyBackground = '#EBEBF2';
|
|
37
|
+
textKeyColor = '#FFFFFF';
|
|
38
|
+
}
|
|
21
39
|
_react.default.useImperativeHandle(ref, () => ({
|
|
22
40
|
focus() {
|
|
23
41
|
const node = (0, _reactNative.findNodeHandle)(nativeRef.current);
|
|
@@ -40,8 +58,14 @@ const InputCalculator = /*#__PURE__*/_react.default.forwardRef((props, ref) => {
|
|
|
40
58
|
...props,
|
|
41
59
|
ref: nativeRef,
|
|
42
60
|
onChange: _onChange,
|
|
61
|
+
onKeyPress: onKeyPress,
|
|
43
62
|
value: text,
|
|
44
|
-
keybardColor: (0, _reactNative.processColor)(
|
|
63
|
+
keybardColor: (0, _reactNative.processColor)(keyboardColor),
|
|
64
|
+
customKeyText: customKeyText,
|
|
65
|
+
customKeyBackground: keyBackground,
|
|
66
|
+
customKeyTextColor: textKeyColor,
|
|
67
|
+
customKeyState: customKeyState,
|
|
68
|
+
onCustomKeyEvent: onCustomKeyEvent
|
|
45
69
|
});
|
|
46
70
|
});
|
|
47
71
|
var _default = exports.default = InputCalculator;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_react","_interopRequireDefault","require","_reactNative","_jsxRuntime","e","__esModule","default","NAME","NativeInput","requireNativeComponent","InputCalculator","React","forwardRef","props","ref","nativeRef","useRef","_onChange","event","currentText","nativeEvent","text","onChange","onChangeText","defaultValue","useImperativeHandle","focus","node","findNodeHandle","current","config","UIManager","getViewManagerConfig","Commands","dispatchViewManagerCommand","blur","jsx","value","keybardColor","processColor","
|
|
1
|
+
{"version":3,"names":["_react","_interopRequireDefault","require","_reactNative","_jsxRuntime","e","__esModule","default","NAME","NativeInput","requireNativeComponent","InputCalculator","React","forwardRef","customKeyBackground","keyboardColor","customKeyText","onKeyPress","customKeyState","onCustomKeyEvent","props","ref","nativeRef","useRef","_onChange","event","currentText","nativeEvent","text","onChange","onChangeText","defaultValue","keyBackground","textKeyColor","useImperativeHandle","focus","node","findNodeHandle","current","config","UIManager","getViewManagerConfig","Commands","dispatchViewManagerCommand","blur","jsx","value","keybardColor","processColor","customKeyTextColor","_default","exports"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,YAAA,GAAAD,OAAA;AASsB,IAAAE,WAAA,GAAAF,OAAA;AAAA,SAAAD,uBAAAI,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAEtB,MAAMG,IAAI,GAAG,oBAAoB;AACjC,MAAMC,WAAW,GAAG,IAAAC,mCAAsB,EAAMF,IAAI,CAAC;AAmBrD,MAAMG,eAAe,gBAAGC,cAAK,CAACC,UAAU,CAItC,CACE;EACEC,mBAAmB,GAAG,SAAS;EAC/BC,aAAa,GAAG,EAAE;EAClBC,aAAa;EACbC,UAAU;EACVC,cAAc,GAAG,SAAS;EAC1BC,gBAAgB;EAChB,GAAGC;AACL,CAAC,EACDC,GAAG,KACA;EACH,MAAMC,SAAS,GAAGV,cAAK,CAACW,MAAM,CAAM,IAAI,CAAC;EAEzC,MAAMC,SAAS,GACbC,KAAqD,IAClD;IACH,MAAMC,WAAW,GAAGD,KAAK,CAACE,WAAW,CAACC,IAAI;IAC1CR,KAAK,CAACS,QAAQ,IAAIT,KAAK,CAACS,QAAQ,CAACJ,KAAK,CAAC;IACvCL,KAAK,CAACU,YAAY,IAAIV,KAAK,CAACU,YAAY,CAACJ,WAAW,CAAC;EACvD,CAAC;EAED,MAAME,IAAI,GAAGR,KAAK,CAACQ,IAAI,IAAIR,KAAK,CAACW,YAAY,IAAI,EAAE;EACnD,IAAIC,aAAa,GAAG,SAAS;EAC7B,IAAIC,YAAY,GAAG,SAAS;EAE5B,IAAInB,mBAAmB,KAAK,SAAS,EAAE;IACrCkB,aAAa,GAAG,SAAS;IACzBC,YAAY,GAAG,SAAS;EAC1B;EAEA,IAAIf,cAAc,KAAK,SAAS,EAAE;IAChCc,aAAa,GAAG,SAAS;IACzBC,YAAY,GAAG,SAAS;EAC1B;EAEArB,cAAK,CAACsB,mBAAmB,CAACb,GAAG,EAAE,OAAO;IACpCc,KAAKA,CAAA,EAAG;MACN,MAAMC,IAAI,GAAG,IAAAC,2BAAc,EAACf,SAAS,CAACgB,OAAO,CAAC;MAC9C,IAAI,CAACF,IAAI,EAAE;MACX,MAAMG,MAAM,GAAGC,sBAAS,CAACC,oBAAoB,CAACjC,IAAI,CAAC;MACnD,IAAI+B,MAAM,EAAEG,QAAQ,EAAEP,KAAK,IAAI,IAAI,EAAE;QACnCK,sBAAS,CAACG,0BAA0B,CAACP,IAAI,EAAEG,MAAM,CAACG,QAAQ,CAACP,KAAK,EAAE,EAAE,CAAC;MACvE;IACF,CAAC;IACDS,IAAIA,CAAA,EAAG;MACL,MAAMR,IAAI,GAAG,IAAAC,2BAAc,EAACf,SAAS,CAACgB,OAAO,CAAC;MAC9C,IAAI,CAACF,IAAI,EAAE;MACX,MAAMG,MAAM,GAAGC,sBAAS,CAACC,oBAAoB,CAACjC,IAAI,CAAC;MACnD,IAAI+B,MAAM,EAAEG,QAAQ,EAAEE,IAAI,IAAI,IAAI,EAAE;QAClCJ,sBAAS,CAACG,0BAA0B,CAACP,IAAI,EAAEG,MAAM,CAACG,QAAQ,CAACE,IAAI,EAAE,EAAE,CAAC;MACtE;IACF;EACF,CAAC,CAAC,CAAC;EAEH,oBACE,IAAAxC,WAAA,CAAAyC,GAAA,EAACpC,WAAW;IAAA,GACNW,KAAK;IACTC,GAAG,EAAEC,SAAU;IACfO,QAAQ,EAAEL,SAAU;IACpBP,UAAU,EAAEA,UAAW;IACvB6B,KAAK,EAAElB,IAAK;IACZmB,YAAY,EAAE,IAAAC,yBAAY,EAACjC,aAAa,CAAE;IAC1CC,aAAa,EAAEA,aAAc;IAC7BF,mBAAmB,EAAEkB,aAAc;IACnCiB,kBAAkB,EAAEhB,YAAa;IACjCf,cAAc,EAAEA,cAAe;IAC/BC,gBAAgB,EAAEA;EAAiB,CACpC,CAAC;AAEN,CACF,CAAC;AAAC,IAAA+B,QAAA,GAAAC,OAAA,CAAA5C,OAAA,GAEaI,eAAe","ignoreList":[]}
|
package/lib/module/index.js
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
import React from 'react';
|
|
4
|
-
import { processColor,
|
|
5
|
-
import { requireNativeComponent } from 'react-native';
|
|
4
|
+
import { findNodeHandle, processColor, requireNativeComponent, UIManager } from 'react-native';
|
|
6
5
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
7
6
|
const NAME = 'RCTInputCalculator';
|
|
8
7
|
const NativeInput = requireNativeComponent(NAME);
|
|
9
|
-
const InputCalculator = /*#__PURE__*/React.forwardRef((
|
|
8
|
+
const InputCalculator = /*#__PURE__*/React.forwardRef(({
|
|
9
|
+
customKeyBackground = 'default',
|
|
10
|
+
keyboardColor = '',
|
|
11
|
+
customKeyText,
|
|
12
|
+
onKeyPress,
|
|
13
|
+
customKeyState = 'default',
|
|
14
|
+
onCustomKeyEvent,
|
|
15
|
+
...props
|
|
16
|
+
}, ref) => {
|
|
10
17
|
const nativeRef = React.useRef(null);
|
|
11
18
|
const _onChange = event => {
|
|
12
19
|
const currentText = event.nativeEvent.text;
|
|
@@ -14,6 +21,16 @@ const InputCalculator = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
|
14
21
|
props.onChangeText && props.onChangeText(currentText);
|
|
15
22
|
};
|
|
16
23
|
const text = props.text ?? props.defaultValue ?? '';
|
|
24
|
+
let keyBackground = '#D8D8D8';
|
|
25
|
+
let textKeyColor = '#000000';
|
|
26
|
+
if (customKeyBackground === 'primary') {
|
|
27
|
+
keyBackground = '#EB2F96';
|
|
28
|
+
textKeyColor = '#FFFFFF';
|
|
29
|
+
}
|
|
30
|
+
if (customKeyState === 'disable') {
|
|
31
|
+
keyBackground = '#EBEBF2';
|
|
32
|
+
textKeyColor = '#FFFFFF';
|
|
33
|
+
}
|
|
17
34
|
React.useImperativeHandle(ref, () => ({
|
|
18
35
|
focus() {
|
|
19
36
|
const node = findNodeHandle(nativeRef.current);
|
|
@@ -36,8 +53,14 @@ const InputCalculator = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
|
36
53
|
...props,
|
|
37
54
|
ref: nativeRef,
|
|
38
55
|
onChange: _onChange,
|
|
56
|
+
onKeyPress: onKeyPress,
|
|
39
57
|
value: text,
|
|
40
|
-
keybardColor: processColor(
|
|
58
|
+
keybardColor: processColor(keyboardColor),
|
|
59
|
+
customKeyText: customKeyText,
|
|
60
|
+
customKeyBackground: keyBackground,
|
|
61
|
+
customKeyTextColor: textKeyColor,
|
|
62
|
+
customKeyState: customKeyState,
|
|
63
|
+
onCustomKeyEvent: onCustomKeyEvent
|
|
41
64
|
});
|
|
42
65
|
});
|
|
43
66
|
export default InputCalculator;
|
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["React","
|
|
1
|
+
{"version":3,"names":["React","findNodeHandle","processColor","requireNativeComponent","UIManager","jsx","_jsx","NAME","NativeInput","InputCalculator","forwardRef","customKeyBackground","keyboardColor","customKeyText","onKeyPress","customKeyState","onCustomKeyEvent","props","ref","nativeRef","useRef","_onChange","event","currentText","nativeEvent","text","onChange","onChangeText","defaultValue","keyBackground","textKeyColor","useImperativeHandle","focus","node","current","config","getViewManagerConfig","Commands","dispatchViewManagerCommand","blur","value","keybardColor","customKeyTextColor"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,OAAOA,KAAK,MAAM,OAAO;AACzB,SAEEC,cAAc,EAEdC,YAAY,EACZC,sBAAsB,EAGtBC,SAAS,QACJ,cAAc;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAEtB,MAAMC,IAAI,GAAG,oBAAoB;AACjC,MAAMC,WAAW,GAAGL,sBAAsB,CAAMI,IAAI,CAAC;AAmBrD,MAAME,eAAe,gBAAGT,KAAK,CAACU,UAAU,CAItC,CACE;EACEC,mBAAmB,GAAG,SAAS;EAC/BC,aAAa,GAAG,EAAE;EAClBC,aAAa;EACbC,UAAU;EACVC,cAAc,GAAG,SAAS;EAC1BC,gBAAgB;EAChB,GAAGC;AACL,CAAC,EACDC,GAAG,KACA;EACH,MAAMC,SAAS,GAAGnB,KAAK,CAACoB,MAAM,CAAM,IAAI,CAAC;EAEzC,MAAMC,SAAS,GACbC,KAAqD,IAClD;IACH,MAAMC,WAAW,GAAGD,KAAK,CAACE,WAAW,CAACC,IAAI;IAC1CR,KAAK,CAACS,QAAQ,IAAIT,KAAK,CAACS,QAAQ,CAACJ,KAAK,CAAC;IACvCL,KAAK,CAACU,YAAY,IAAIV,KAAK,CAACU,YAAY,CAACJ,WAAW,CAAC;EACvD,CAAC;EAED,MAAME,IAAI,GAAGR,KAAK,CAACQ,IAAI,IAAIR,KAAK,CAACW,YAAY,IAAI,EAAE;EACnD,IAAIC,aAAa,GAAG,SAAS;EAC7B,IAAIC,YAAY,GAAG,SAAS;EAE5B,IAAInB,mBAAmB,KAAK,SAAS,EAAE;IACrCkB,aAAa,GAAG,SAAS;IACzBC,YAAY,GAAG,SAAS;EAC1B;EAEA,IAAIf,cAAc,KAAK,SAAS,EAAE;IAChCc,aAAa,GAAG,SAAS;IACzBC,YAAY,GAAG,SAAS;EAC1B;EAEA9B,KAAK,CAAC+B,mBAAmB,CAACb,GAAG,EAAE,OAAO;IACpCc,KAAKA,CAAA,EAAG;MACN,MAAMC,IAAI,GAAGhC,cAAc,CAACkB,SAAS,CAACe,OAAO,CAAC;MAC9C,IAAI,CAACD,IAAI,EAAE;MACX,MAAME,MAAM,GAAG/B,SAAS,CAACgC,oBAAoB,CAAC7B,IAAI,CAAC;MACnD,IAAI4B,MAAM,EAAEE,QAAQ,EAAEL,KAAK,IAAI,IAAI,EAAE;QACnC5B,SAAS,CAACkC,0BAA0B,CAACL,IAAI,EAAEE,MAAM,CAACE,QAAQ,CAACL,KAAK,EAAE,EAAE,CAAC;MACvE;IACF,CAAC;IACDO,IAAIA,CAAA,EAAG;MACL,MAAMN,IAAI,GAAGhC,cAAc,CAACkB,SAAS,CAACe,OAAO,CAAC;MAC9C,IAAI,CAACD,IAAI,EAAE;MACX,MAAME,MAAM,GAAG/B,SAAS,CAACgC,oBAAoB,CAAC7B,IAAI,CAAC;MACnD,IAAI4B,MAAM,EAAEE,QAAQ,EAAEE,IAAI,IAAI,IAAI,EAAE;QAClCnC,SAAS,CAACkC,0BAA0B,CAACL,IAAI,EAAEE,MAAM,CAACE,QAAQ,CAACE,IAAI,EAAE,EAAE,CAAC;MACtE;IACF;EACF,CAAC,CAAC,CAAC;EAEH,oBACEjC,IAAA,CAACE,WAAW;IAAA,GACNS,KAAK;IACTC,GAAG,EAAEC,SAAU;IACfO,QAAQ,EAAEL,SAAU;IACpBP,UAAU,EAAEA,UAAW;IACvB0B,KAAK,EAAEf,IAAK;IACZgB,YAAY,EAAEvC,YAAY,CAACU,aAAa,CAAE;IAC1CC,aAAa,EAAEA,aAAc;IAC7BF,mBAAmB,EAAEkB,aAAc;IACnCa,kBAAkB,EAAEZ,YAAa;IACjCf,cAAc,EAAEA,cAAe;IAC/BC,gBAAgB,EAAEA;EAAiB,CACpC,CAAC;AAEN,CACF,CAAC;AAED,eAAeP,eAAe","ignoreList":[]}
|
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { type
|
|
2
|
+
import { type ColorValue, type TextInputProps } from 'react-native';
|
|
3
|
+
type KeyPressEvent = {
|
|
4
|
+
nativeEvent: {
|
|
5
|
+
key: string;
|
|
6
|
+
};
|
|
7
|
+
};
|
|
3
8
|
interface InputCalculatorProps extends TextInputProps {
|
|
4
9
|
text?: string | undefined;
|
|
5
10
|
keyboardColor?: ColorValue;
|
|
11
|
+
onKeyPress?: (e: KeyPressEvent) => void;
|
|
12
|
+
customKeyText?: string | undefined;
|
|
13
|
+
customKeyBackground?: string | undefined;
|
|
14
|
+
customKeyState?: string | undefined;
|
|
15
|
+
onCustomKeyEvent?: () => void;
|
|
6
16
|
}
|
|
7
17
|
export type InputCalculatorRef = {
|
|
8
18
|
focus: () => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EACL,KAAK,UAAU,EAMf,KAAK,cAAc,EAEpB,MAAM,cAAc,CAAC;AAKtB,KAAK,aAAa,GAAG;IAAE,WAAW,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC;AAEtD,UAAU,oBAAqB,SAAQ,cAAc;IACnD,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,aAAa,CAAC,EAAE,UAAU,CAAC;IAC3B,UAAU,CAAC,EAAE,CAAC,CAAC,EAAE,aAAa,KAAK,IAAI,CAAC;IACxC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,mBAAmB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;CAC/B;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,IAAI,EAAE,MAAM,IAAI,CAAC;CAClB,CAAC;AAEF,QAAA,MAAM,eAAe,iGA2EpB,CAAC;AAEF,eAAe,eAAe,CAAC"}
|
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { type
|
|
2
|
+
import { type ColorValue, type TextInputProps } from 'react-native';
|
|
3
|
+
type KeyPressEvent = {
|
|
4
|
+
nativeEvent: {
|
|
5
|
+
key: string;
|
|
6
|
+
};
|
|
7
|
+
};
|
|
3
8
|
interface InputCalculatorProps extends TextInputProps {
|
|
4
9
|
text?: string | undefined;
|
|
5
10
|
keyboardColor?: ColorValue;
|
|
11
|
+
onKeyPress?: (e: KeyPressEvent) => void;
|
|
12
|
+
customKeyText?: string | undefined;
|
|
13
|
+
customKeyBackground?: string | undefined;
|
|
14
|
+
customKeyState?: string | undefined;
|
|
15
|
+
onCustomKeyEvent?: () => void;
|
|
6
16
|
}
|
|
7
17
|
export type InputCalculatorRef = {
|
|
8
18
|
focus: () => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EACL,KAAK,UAAU,EAMf,KAAK,cAAc,EAEpB,MAAM,cAAc,CAAC;AAKtB,KAAK,aAAa,GAAG;IAAE,WAAW,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC;AAEtD,UAAU,oBAAqB,SAAQ,cAAc;IACnD,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,aAAa,CAAC,EAAE,UAAU,CAAC;IAC3B,UAAU,CAAC,EAAE,CAAC,CAAC,EAAE,aAAa,KAAK,IAAI,CAAC;IACxC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,mBAAmB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;CAC/B;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,IAAI,EAAE,MAAM,IAAI,CAAC;CAClB,CAAC;AAEF,QAAA,MAAM,eAAe,iGA2EpB,CAAC;AAEF,eAAe,eAAe,CAAC"}
|
package/package.json
CHANGED
package/src/index.tsx
CHANGED
|
@@ -1,21 +1,28 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import {
|
|
3
|
+
type ColorValue,
|
|
4
|
+
findNodeHandle,
|
|
3
5
|
type NativeSyntheticEvent,
|
|
6
|
+
processColor,
|
|
7
|
+
requireNativeComponent,
|
|
4
8
|
type TextInputChangeEventData,
|
|
5
9
|
type TextInputProps,
|
|
6
|
-
type ColorValue,
|
|
7
|
-
processColor,
|
|
8
10
|
UIManager,
|
|
9
|
-
findNodeHandle,
|
|
10
11
|
} from 'react-native';
|
|
11
|
-
import { requireNativeComponent } from 'react-native';
|
|
12
12
|
|
|
13
13
|
const NAME = 'RCTInputCalculator';
|
|
14
14
|
const NativeInput = requireNativeComponent<any>(NAME);
|
|
15
15
|
|
|
16
|
+
type KeyPressEvent = { nativeEvent: { key: string } };
|
|
17
|
+
|
|
16
18
|
interface InputCalculatorProps extends TextInputProps {
|
|
17
19
|
text?: string | undefined;
|
|
18
20
|
keyboardColor?: ColorValue;
|
|
21
|
+
onKeyPress?: (e: KeyPressEvent) => void;
|
|
22
|
+
customKeyText?: string | undefined;
|
|
23
|
+
customKeyBackground?: string | undefined;
|
|
24
|
+
customKeyState?: string | undefined;
|
|
25
|
+
onCustomKeyEvent?: () => void;
|
|
19
26
|
}
|
|
20
27
|
|
|
21
28
|
export type InputCalculatorRef = {
|
|
@@ -23,8 +30,22 @@ export type InputCalculatorRef = {
|
|
|
23
30
|
blur: () => void;
|
|
24
31
|
};
|
|
25
32
|
|
|
26
|
-
const InputCalculator = React.forwardRef<
|
|
27
|
-
|
|
33
|
+
const InputCalculator = React.forwardRef<
|
|
34
|
+
InputCalculatorRef,
|
|
35
|
+
InputCalculatorProps
|
|
36
|
+
>(
|
|
37
|
+
(
|
|
38
|
+
{
|
|
39
|
+
customKeyBackground = 'default',
|
|
40
|
+
keyboardColor = '',
|
|
41
|
+
customKeyText,
|
|
42
|
+
onKeyPress,
|
|
43
|
+
customKeyState = 'default',
|
|
44
|
+
onCustomKeyEvent,
|
|
45
|
+
...props
|
|
46
|
+
},
|
|
47
|
+
ref
|
|
48
|
+
) => {
|
|
28
49
|
const nativeRef = React.useRef<any>(null);
|
|
29
50
|
|
|
30
51
|
const _onChange = (
|
|
@@ -36,6 +57,18 @@ const InputCalculator = React.forwardRef<InputCalculatorRef, InputCalculatorProp
|
|
|
36
57
|
};
|
|
37
58
|
|
|
38
59
|
const text = props.text ?? props.defaultValue ?? '';
|
|
60
|
+
let keyBackground = '#D8D8D8';
|
|
61
|
+
let textKeyColor = '#000000';
|
|
62
|
+
|
|
63
|
+
if (customKeyBackground === 'primary') {
|
|
64
|
+
keyBackground = '#EB2F96';
|
|
65
|
+
textKeyColor = '#FFFFFF';
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (customKeyState === 'disable') {
|
|
69
|
+
keyBackground = '#EBEBF2';
|
|
70
|
+
textKeyColor = '#FFFFFF';
|
|
71
|
+
}
|
|
39
72
|
|
|
40
73
|
React.useImperativeHandle(ref, () => ({
|
|
41
74
|
focus() {
|
|
@@ -61,8 +94,14 @@ const InputCalculator = React.forwardRef<InputCalculatorRef, InputCalculatorProp
|
|
|
61
94
|
{...props}
|
|
62
95
|
ref={nativeRef}
|
|
63
96
|
onChange={_onChange}
|
|
97
|
+
onKeyPress={onKeyPress}
|
|
64
98
|
value={text}
|
|
65
|
-
keybardColor={processColor(
|
|
99
|
+
keybardColor={processColor(keyboardColor)}
|
|
100
|
+
customKeyText={customKeyText}
|
|
101
|
+
customKeyBackground={keyBackground}
|
|
102
|
+
customKeyTextColor={textKeyColor}
|
|
103
|
+
customKeyState={customKeyState}
|
|
104
|
+
onCustomKeyEvent={onCustomKeyEvent}
|
|
66
105
|
/>
|
|
67
106
|
);
|
|
68
107
|
}
|