react-native-controlled-input 0.17.0 → 0.19.0
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.
|
@@ -2,8 +2,10 @@ package com.controlledinput
|
|
|
2
2
|
|
|
3
3
|
import android.content.Context
|
|
4
4
|
import android.util.AttributeSet
|
|
5
|
+
import android.util.Log
|
|
5
6
|
import android.util.TypedValue
|
|
6
7
|
import android.view.View
|
|
8
|
+
import android.view.ViewTreeObserver
|
|
7
9
|
import android.view.inputmethod.InputMethodManager
|
|
8
10
|
import android.widget.EditText
|
|
9
11
|
import android.widget.LinearLayout
|
|
@@ -25,6 +27,7 @@ import androidx.savedstate.SavedStateRegistryOwner
|
|
|
25
27
|
import androidx.savedstate.setViewTreeSavedStateRegistryOwner
|
|
26
28
|
import com.facebook.react.bridge.ReactContext
|
|
27
29
|
import com.facebook.react.uimanager.UIManagerHelper
|
|
30
|
+
import com.facebook.react.uimanager.events.Event
|
|
28
31
|
import kotlinx.coroutines.flow.MutableStateFlow
|
|
29
32
|
|
|
30
33
|
/**
|
|
@@ -35,6 +38,9 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
|
|
35
38
|
* @see expo.modules.kotlin.views.ExpoView
|
|
36
39
|
*/
|
|
37
40
|
class ControlledInputView : LinearLayout, LifecycleOwner {
|
|
41
|
+
companion object {
|
|
42
|
+
private const val TAG = "ControlledInputView"
|
|
43
|
+
}
|
|
38
44
|
constructor(context: Context) : super(context) {
|
|
39
45
|
configureComponent(context)
|
|
40
46
|
}
|
|
@@ -61,6 +67,13 @@ class ControlledInputView : LinearLayout, LifecycleOwner {
|
|
|
61
67
|
private var usesLocalFallbackLifecycle = false
|
|
62
68
|
private var windowLifecycleBound = false
|
|
63
69
|
|
|
70
|
+
/**
|
|
71
|
+
* True while we are in the focus-restoration dance:
|
|
72
|
+
* proxy stole Android focus from Compose → onBlur fired → we're restoring Compose focus.
|
|
73
|
+
* During this window the second onFocus must NOT call requestFocusProxy() again.
|
|
74
|
+
*/
|
|
75
|
+
private var isRestoringComposeFocus = false
|
|
76
|
+
|
|
64
77
|
/**
|
|
65
78
|
* Invisible EditText that acts as a focus proxy for react-native-keyboard-controller.
|
|
66
79
|
*
|
|
@@ -75,7 +88,9 @@ class ControlledInputView : LinearLayout, LifecycleOwner {
|
|
|
75
88
|
private val focusProxy: EditText by lazy {
|
|
76
89
|
EditText(context).also { proxy ->
|
|
77
90
|
proxy.layoutParams = LayoutParams(0, 0)
|
|
78
|
-
|
|
91
|
+
// Must stay VISIBLE — Android's canTakeFocus() returns false for INVISIBLE/GONE views,
|
|
92
|
+
// causing requestFocus() to silently fail. Use alpha=0 to hide it visually instead.
|
|
93
|
+
proxy.alpha = 0f
|
|
79
94
|
proxy.isFocusableInTouchMode = true
|
|
80
95
|
proxy.showSoftInputOnFocus = false
|
|
81
96
|
proxy.isClickable = false
|
|
@@ -85,21 +100,210 @@ class ControlledInputView : LinearLayout, LifecycleOwner {
|
|
|
85
100
|
}
|
|
86
101
|
|
|
87
102
|
private fun requestFocusProxy() {
|
|
103
|
+
val fontSize = viewModel.inputStyle.value?.fontSize?.toFloat()
|
|
104
|
+
Log.d(TAG, "──── requestFocusProxy ────")
|
|
105
|
+
Log.d(TAG, " fontSize=$fontSize")
|
|
106
|
+
Log.d(TAG, " proxy before: isFocused=${focusProxy.isFocused} size=${focusProxy.width}x${focusProxy.height}")
|
|
107
|
+
|
|
108
|
+
// Sync proxy ID with ControlledInputView's React Native tag BEFORE requestFocus(),
|
|
109
|
+
// so KeyboardAnimationCallback.focusListener sets viewTagFocused = this.id (not -1).
|
|
110
|
+
// Without this, KeyboardAwareScrollView JS sees e.target=-1 → focusWasChanged=false
|
|
111
|
+
// → layout.value never updated → maybeScroll() always returns 0 → no scroll.
|
|
112
|
+
focusProxy.id = this.id
|
|
113
|
+
Log.d(TAG, " proxy.id set to ${focusProxy.id} (= ControlledInputView RN tag)")
|
|
114
|
+
|
|
88
115
|
// Sync textSize so KeyboardControllerSelectionWatcher computes the correct
|
|
89
116
|
// cursor Y via android.text.Layout.getLineBottom() — used as `customHeight`
|
|
90
117
|
// in KeyboardAwareScrollView to determine how far to scroll.
|
|
91
|
-
|
|
92
|
-
focusProxy.setTextSize(TypedValue.COMPLEX_UNIT_SP,
|
|
118
|
+
fontSize?.let {
|
|
119
|
+
focusProxy.setTextSize(TypedValue.COMPLEX_UNIT_SP, it)
|
|
120
|
+
Log.d(TAG, " proxy textSize set to ${focusProxy.textSize}px (${it}sp)")
|
|
93
121
|
}
|
|
122
|
+
|
|
94
123
|
focusProxy.requestFocus()
|
|
124
|
+
Log.d(TAG, " proxy after requestFocus: isFocused=${focusProxy.isFocused} hasFocus=${focusProxy.hasFocus()}")
|
|
125
|
+
|
|
126
|
+
if (focusProxy.isFocused) {
|
|
127
|
+
// Proxy stole Android focus from AndroidComposeView → Compose will fire onBlur.
|
|
128
|
+
// Mark restoration mode so onBlur knows to recover (not dispatch BlurEvent to JS).
|
|
129
|
+
isRestoringComposeFocus = true
|
|
130
|
+
Log.d(TAG, " isRestoringComposeFocus=true (proxy has Android focus)")
|
|
131
|
+
}
|
|
132
|
+
|
|
95
133
|
// setSelection triggers a selection change (lastSelectionStart starts at -1),
|
|
96
134
|
// guaranteeing the watcher fires on the next pre-draw frame even if focus
|
|
97
135
|
// was just transferred.
|
|
98
136
|
focusProxy.setSelection(0)
|
|
137
|
+
Log.d(TAG, " proxy selectionStart=${focusProxy.selectionStart} layout=${focusProxy.layout != null}")
|
|
138
|
+
|
|
139
|
+
// Log absolute screen position — this is what keyboard-controller reads for scroll calculation
|
|
140
|
+
val loc = IntArray(2)
|
|
141
|
+
focusProxy.getLocationOnScreen(loc)
|
|
142
|
+
Log.d(TAG, " proxy screenLocation x=${loc[0]} y=${loc[1]} → absoluteY for KBC=${loc[1]}px")
|
|
143
|
+
Log.d(TAG, "──────────────────────────")
|
|
99
144
|
}
|
|
100
145
|
|
|
101
146
|
private fun clearFocusProxy() {
|
|
147
|
+
Log.d(TAG, "clearFocusProxy: proxy.isFocused=${focusProxy.isFocused} hasFocus=${focusProxy.hasFocus()}")
|
|
102
148
|
focusProxy.clearFocus()
|
|
149
|
+
Log.d(TAG, "clearFocusProxy: after clearFocus isFocused=${focusProxy.isFocused}")
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Fires when the proxy loses Android focus (i.e. after composeView.requestFocus() restores
|
|
154
|
+
* Compose). At this point KBC's listener has already cleared lastFocusedInput (KBC registered
|
|
155
|
+
* its ViewTreeObserver listener before us → it fires first). We post restoreKbcTracking() to
|
|
156
|
+
* run after all synchronous focus-change handlers complete.
|
|
157
|
+
*/
|
|
158
|
+
private val proxyFocusLostListener =
|
|
159
|
+
ViewTreeObserver.OnGlobalFocusChangeListener { oldFocus, newFocus ->
|
|
160
|
+
// Fire for ANY proxy focus loss while we're in the restoration dance.
|
|
161
|
+
// newFocus can be null (proxy→null→AndroidComposeView, two steps on first focus)
|
|
162
|
+
// or AndroidComposeView directly (proxy→AndroidComposeView, subsequent focuses).
|
|
163
|
+
// Both cases need restoreKbcTracking(); KBC's null→AndroidComposeView transition does
|
|
164
|
+
// NOT clear lastFocusedInput, so restoring it once is enough for both paths.
|
|
165
|
+
if (oldFocus == focusProxy && isRestoringComposeFocus) {
|
|
166
|
+
Log.d(
|
|
167
|
+
TAG,
|
|
168
|
+
"proxyFocusLostListener: proxy → ${newFocus?.javaClass?.simpleName ?: "null"}, posting restoreKbcTracking()",
|
|
169
|
+
)
|
|
170
|
+
post { restoreKbcTracking() }
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* EdgeToEdgeViewRegistry.get() → callback → FocusedInputObserver.
|
|
176
|
+
* Null if react-native-keyboard-controller is missing or not initialized.
|
|
177
|
+
*/
|
|
178
|
+
private fun resolveKbcFocusedInputObserver(): Any? {
|
|
179
|
+
try {
|
|
180
|
+
val registryClass =
|
|
181
|
+
Class.forName("com.reactnativekeyboardcontroller.views.EdgeToEdgeViewRegistry")
|
|
182
|
+
val registryInstance = registryClass.getField("INSTANCE").get(null)
|
|
183
|
+
val edgeToEdgeView =
|
|
184
|
+
registryClass.getDeclaredMethod("get").invoke(registryInstance)
|
|
185
|
+
?: run {
|
|
186
|
+
Log.w(TAG, "resolveKbcFocusedInputObserver: EdgeToEdgeViewRegistry.get() == null")
|
|
187
|
+
return null
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
val callbackField =
|
|
191
|
+
edgeToEdgeView.javaClass.declaredFields.firstOrNull {
|
|
192
|
+
it.type.simpleName == "KeyboardAnimationCallback"
|
|
193
|
+
}
|
|
194
|
+
?: run {
|
|
195
|
+
Log.w(TAG, "resolveKbcFocusedInputObserver: KeyboardAnimationCallback field not found")
|
|
196
|
+
return null
|
|
197
|
+
}
|
|
198
|
+
callbackField.isAccessible = true
|
|
199
|
+
val callback =
|
|
200
|
+
callbackField.get(edgeToEdgeView)
|
|
201
|
+
?: run {
|
|
202
|
+
Log.w(TAG, "resolveKbcFocusedInputObserver: callback == null")
|
|
203
|
+
return null
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
val observerField =
|
|
207
|
+
callback.javaClass.declaredFields.firstOrNull {
|
|
208
|
+
it.type.simpleName == "FocusedInputObserver"
|
|
209
|
+
}
|
|
210
|
+
?: run {
|
|
211
|
+
Log.w(TAG, "resolveKbcFocusedInputObserver: FocusedInputObserver field not found")
|
|
212
|
+
return null
|
|
213
|
+
}
|
|
214
|
+
observerField.isAccessible = true
|
|
215
|
+
return observerField.get(callback)
|
|
216
|
+
?: run {
|
|
217
|
+
Log.w(TAG, "resolveKbcFocusedInputObserver: layoutObserver == null")
|
|
218
|
+
null
|
|
219
|
+
}
|
|
220
|
+
} catch (_: ClassNotFoundException) {
|
|
221
|
+
Log.d(TAG, "resolveKbcFocusedInputObserver: keyboard-controller not on classpath")
|
|
222
|
+
return null
|
|
223
|
+
} catch (e: Exception) {
|
|
224
|
+
Log.w(TAG, "resolveKbcFocusedInputObserver: ${e.javaClass.simpleName}: ${e.message}")
|
|
225
|
+
return null
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/** Approximate one line height in dp for JS customHeight when proxy has no Layout yet. */
|
|
230
|
+
private fun approximateSelectionEndYDp(): Double {
|
|
231
|
+
viewModel.inputStyle.value?.fontSize?.toDouble()?.takeIf { it > 0 }?.let { return it }
|
|
232
|
+
val dm = resources.displayMetrics
|
|
233
|
+
return (focusProxy.textSize / dm.density).toDouble().coerceAtLeast(12.0)
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Synthetic topFocusedInputSelectionChanged without a compile dependency on KBC.
|
|
238
|
+
* Helps older KeyboardAwareScrollView when proxy never gets android.text.Layout in time.
|
|
239
|
+
*/
|
|
240
|
+
private fun dispatchSyntheticKbcSelectionEvent(observer: Any) {
|
|
241
|
+
val reactContext = context as? ReactContext ?: return
|
|
242
|
+
try {
|
|
243
|
+
val epField = observer.javaClass.getDeclaredField("eventPropagationView")
|
|
244
|
+
epField.isAccessible = true
|
|
245
|
+
val propagationId = (epField.get(observer) as View).id
|
|
246
|
+
|
|
247
|
+
val surfaceId = UIManagerHelper.getSurfaceId(this)
|
|
248
|
+
val targetId = id
|
|
249
|
+
val endY = approximateSelectionEndYDp()
|
|
250
|
+
|
|
251
|
+
val dataClz =
|
|
252
|
+
Class.forName("com.reactnativekeyboardcontroller.events.FocusedInputSelectionChangedEventData")
|
|
253
|
+
val dataCtor =
|
|
254
|
+
dataClz.declaredConstructors.singleOrNull { it.parameterTypes.size == 7 }
|
|
255
|
+
?: run {
|
|
256
|
+
Log.w(TAG, "dispatchSyntheticKbcSelectionEvent: no 7-arg data ctor")
|
|
257
|
+
return
|
|
258
|
+
}
|
|
259
|
+
dataCtor.isAccessible = true
|
|
260
|
+
val data =
|
|
261
|
+
dataCtor.newInstance(targetId, 0.0, 0.0, 0.0, endY, 0, 0)
|
|
262
|
+
|
|
263
|
+
val eventClz =
|
|
264
|
+
Class.forName("com.reactnativekeyboardcontroller.events.FocusedInputSelectionChangedEvent")
|
|
265
|
+
val eventCtor =
|
|
266
|
+
eventClz.getConstructor(
|
|
267
|
+
Int::class.javaPrimitiveType,
|
|
268
|
+
Int::class.javaPrimitiveType,
|
|
269
|
+
dataClz,
|
|
270
|
+
)
|
|
271
|
+
val event = eventCtor.newInstance(surfaceId, propagationId, data) as Event<*>
|
|
272
|
+
|
|
273
|
+
UIManagerHelper.getEventDispatcherForReactTag(reactContext, propagationId)
|
|
274
|
+
?.dispatchEvent(event)
|
|
275
|
+
Log.d(
|
|
276
|
+
TAG,
|
|
277
|
+
"dispatchSyntheticKbcSelectionEvent: propagationId=$propagationId target=$targetId endY(dp)=$endY",
|
|
278
|
+
)
|
|
279
|
+
} catch (e: Exception) {
|
|
280
|
+
Log.w(TAG, "dispatchSyntheticKbcSelectionEvent: ${e.javaClass.simpleName}: ${e.message}")
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Reflection: lastFocusedInput = focusProxy, syncUpLayout(), then synthetic selection
|
|
286
|
+
* so JS gets customHeight (selection.end.y) without waiting for KeyboardControllerSelectionWatcher.
|
|
287
|
+
*/
|
|
288
|
+
private fun restoreKbcTracking() {
|
|
289
|
+
Log.d(TAG, "restoreKbcTracking: starting reflection chain")
|
|
290
|
+
try {
|
|
291
|
+
val observer = resolveKbcFocusedInputObserver() ?: return
|
|
292
|
+
|
|
293
|
+
val lastFocusedField = observer.javaClass.getDeclaredField("lastFocusedInput")
|
|
294
|
+
lastFocusedField.isAccessible = true
|
|
295
|
+
lastFocusedField.set(observer, focusProxy)
|
|
296
|
+
Log.d(TAG, "restoreKbcTracking: lastFocusedInput set to focusProxy")
|
|
297
|
+
|
|
298
|
+
val syncMethod = observer.javaClass.getDeclaredMethod("syncUpLayout")
|
|
299
|
+
syncMethod.isAccessible = true
|
|
300
|
+
syncMethod.invoke(observer)
|
|
301
|
+
Log.d(TAG, "restoreKbcTracking: syncUpLayout() invoked")
|
|
302
|
+
|
|
303
|
+
dispatchSyntheticKbcSelectionEvent(observer)
|
|
304
|
+
} catch (e: Exception) {
|
|
305
|
+
Log.w(TAG, "restoreKbcTracking: ${e.javaClass.simpleName}: ${e.message}")
|
|
306
|
+
}
|
|
103
307
|
}
|
|
104
308
|
|
|
105
309
|
private val shouldUseAndroidLayout = true
|
|
@@ -109,6 +313,12 @@ class ControlledInputView : LinearLayout, LifecycleOwner {
|
|
|
109
313
|
// Force proxy bounds to match ControlledInputView so keyboard-controller reads
|
|
110
314
|
// the correct width/height/absolutePosition when the proxy is focused.
|
|
111
315
|
focusProxy.layout(0, 0, width, height)
|
|
316
|
+
if (changed) {
|
|
317
|
+
val loc = IntArray(2)
|
|
318
|
+
getLocationOnScreen(loc)
|
|
319
|
+
Log.d(TAG, "onLayout: view=${width}x${height} screenX=${loc[0]} screenY=${loc[1]}")
|
|
320
|
+
Log.d(TAG, "onLayout: proxy=${focusProxy.width}x${focusProxy.height} (should match view)")
|
|
321
|
+
}
|
|
112
322
|
}
|
|
113
323
|
|
|
114
324
|
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
|
@@ -142,10 +352,15 @@ class ControlledInputView : LinearLayout, LifecycleOwner {
|
|
|
142
352
|
|
|
143
353
|
override fun onAttachedToWindow() {
|
|
144
354
|
super.onAttachedToWindow()
|
|
355
|
+
Log.d(TAG, "onAttachedToWindow: id=$id")
|
|
356
|
+
viewTreeObserver.addOnGlobalFocusChangeListener(proxyFocusLostListener)
|
|
145
357
|
bindComposeToWindowLifecycle()
|
|
146
358
|
}
|
|
147
359
|
|
|
148
360
|
override fun onDetachedFromWindow() {
|
|
361
|
+
Log.d(TAG, "onDetachedFromWindow: id=$id")
|
|
362
|
+
viewTreeObserver.removeOnGlobalFocusChangeListener(proxyFocusLostListener)
|
|
363
|
+
isRestoringComposeFocus = false
|
|
149
364
|
if (usesLocalFallbackLifecycle) {
|
|
150
365
|
lifecycleRegistry.currentState = Lifecycle.State.CREATED
|
|
151
366
|
}
|
|
@@ -190,6 +405,8 @@ class ControlledInputView : LinearLayout, LifecycleOwner {
|
|
|
190
405
|
}
|
|
191
406
|
|
|
192
407
|
fun blur() {
|
|
408
|
+
Log.d(TAG, "blur() called from JS ref")
|
|
409
|
+
isRestoringComposeFocus = false
|
|
193
410
|
blurSignal.value = blurSignal.value + 1
|
|
194
411
|
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
|
195
412
|
imm.hideSoftInputFromWindow(windowToken, 0)
|
|
@@ -198,6 +415,7 @@ class ControlledInputView : LinearLayout, LifecycleOwner {
|
|
|
198
415
|
}
|
|
199
416
|
|
|
200
417
|
fun focus() {
|
|
418
|
+
Log.d(TAG, "focus() called from JS ref")
|
|
201
419
|
focusSignal.value = focusSignal.value + 1
|
|
202
420
|
}
|
|
203
421
|
|
|
@@ -265,30 +483,47 @@ class ControlledInputView : LinearLayout, LifecycleOwner {
|
|
|
265
483
|
)
|
|
266
484
|
},
|
|
267
485
|
onFocus = {
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
)
|
|
278
|
-
|
|
486
|
+
Log.d(TAG, "Compose onFocus id=$id isRestoring=$isRestoringComposeFocus")
|
|
487
|
+
if (isRestoringComposeFocus) {
|
|
488
|
+
// Second onFocus triggered by focusRequester.requestFocus() inside the restoration
|
|
489
|
+
// dance — KBC is being synced via reflection, keyboard is showing.
|
|
490
|
+
// Do NOT dispatch FocusEvent again (already sent on first onFocus).
|
|
491
|
+
// Do NOT call requestFocusProxy() again (would cause infinite loop).
|
|
492
|
+
Log.d(TAG, " → restoration onFocus: clearing flag, skipping proxy request")
|
|
493
|
+
isRestoringComposeFocus = false
|
|
494
|
+
} else {
|
|
495
|
+
val surfaceId = UIManagerHelper.getSurfaceId(context)
|
|
496
|
+
val viewId = this@ControlledInputView.id
|
|
497
|
+
UIManagerHelper
|
|
498
|
+
.getEventDispatcherForReactTag(context as ReactContext, viewId)
|
|
499
|
+
?.dispatchEvent(FocusEvent(surfaceId, viewId))
|
|
500
|
+
requestFocusProxy()
|
|
501
|
+
}
|
|
279
502
|
},
|
|
280
503
|
onBlur = {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
)
|
|
290
|
-
|
|
291
|
-
|
|
504
|
+
Log.d(TAG, "Compose onBlur id=$id proxyFocused=${focusProxy.isFocused}")
|
|
505
|
+
if (focusProxy.isFocused) {
|
|
506
|
+
// Proxy stole Android focus from AndroidComposeView → this blur is synthetic.
|
|
507
|
+
// Restore Compose focus so the keyboard stays/re-appears.
|
|
508
|
+
// Do NOT dispatch BlurEvent to JS.
|
|
509
|
+
Log.d(TAG, " → proxy-caused blur: restoring Compose focus")
|
|
510
|
+
post {
|
|
511
|
+
// Give AndroidComposeView Android focus back (needed for showSoftInput to work)
|
|
512
|
+
composeView.requestFocus()
|
|
513
|
+
// Trigger BasicTextField to re-gain Compose focus → shows keyboard → fires onFocus
|
|
514
|
+
focusSignal.value = focusSignal.value + 1
|
|
515
|
+
}
|
|
516
|
+
} else {
|
|
517
|
+
// Real blur (user dismissed keyboard / tapped elsewhere)
|
|
518
|
+
Log.d(TAG, " → real blur: dispatching BlurEvent")
|
|
519
|
+
isRestoringComposeFocus = false
|
|
520
|
+
val surfaceId = UIManagerHelper.getSurfaceId(context)
|
|
521
|
+
val viewId = this@ControlledInputView.id
|
|
522
|
+
UIManagerHelper
|
|
523
|
+
.getEventDispatcherForReactTag(context as ReactContext, viewId)
|
|
524
|
+
?.dispatchEvent(BlurEvent(surfaceId, viewId))
|
|
525
|
+
clearFocusProxy()
|
|
526
|
+
}
|
|
292
527
|
},
|
|
293
528
|
focusRequester = focusRequester
|
|
294
529
|
)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-controlled-input",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.0",
|
|
4
4
|
"description": "React Native controlled TextInput with strict value sync (Fabric)",
|
|
5
5
|
"main": "./lib/module/index.js",
|
|
6
6
|
"types": "./lib/typescript/src/index.d.ts",
|
|
@@ -82,6 +82,7 @@
|
|
|
82
82
|
"react": "19.2.0",
|
|
83
83
|
"react-native": "0.83.0",
|
|
84
84
|
"react-native-builder-bob": "^0.40.17",
|
|
85
|
+
"react-native-worklets": "0.8.1",
|
|
85
86
|
"release-it": "^19.0.4",
|
|
86
87
|
"turbo": "^2.5.6",
|
|
87
88
|
"typescript": "^5.7.3",
|
|
@@ -94,6 +95,9 @@
|
|
|
94
95
|
"workspaces": [
|
|
95
96
|
"example"
|
|
96
97
|
],
|
|
98
|
+
"overrides": {
|
|
99
|
+
"react-native-worklets": "0.8.1"
|
|
100
|
+
},
|
|
97
101
|
"react-native-builder-bob": {
|
|
98
102
|
"source": "src",
|
|
99
103
|
"output": "lib",
|
|
@@ -142,7 +146,10 @@
|
|
|
142
146
|
"git": {
|
|
143
147
|
"commitMessage": "chore: release ${version}",
|
|
144
148
|
"tagName": "v${version}",
|
|
145
|
-
"requireBranch": [
|
|
149
|
+
"requireBranch": [
|
|
150
|
+
"main",
|
|
151
|
+
"test-keboard--controller"
|
|
152
|
+
]
|
|
146
153
|
},
|
|
147
154
|
"npm": {
|
|
148
155
|
"publish": true,
|