diff --git a/packages/react-native/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js b/packages/react-native/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js index 734b37d3dc3644..ef6296d1c81006 100644 --- a/packages/react-native/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js +++ b/packages/react-native/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js @@ -658,6 +658,7 @@ export const __INTERNAL_VIEW_CONFIG: PartialViewConfig = { }, }, validAttributes: { + acceptDragAndDropTypes: true, maxFontSizeMultiplier: true, adjustsFontSizeToFit: true, minimumFontScale: true, diff --git a/packages/react-native/Libraries/Components/TextInput/TextInput.flow.js b/packages/react-native/Libraries/Components/TextInput/TextInput.flow.js index b273341b328ee2..a97736ded0c9c9 100644 --- a/packages/react-native/Libraries/Components/TextInput/TextInput.flow.js +++ b/packages/react-native/Libraries/Components/TextInput/TextInput.flow.js @@ -405,6 +405,19 @@ export type TextInputIOSProps = $ReadOnly<{ }>; export type TextInputAndroidProps = $ReadOnly<{ + /** + * When provided, the text input will only accept drag and drop events for the specified + * mime types. If null or not provided, the text input will accept all types of drag and drop + * events. + * Defaults to null. + * + * *NOTE*: This prop is experimental and its API may change in the future. Use at your own risk. + * + * @platform android + * @see https://developer.android.com/reference/android/content/ClipData for more information on MIME types + */ + experimental_acceptDragAndDropTypes?: ?$ReadOnlyArray, + /** * When provided it will set the color of the cursor (or "caret") in the component. * Unlike the behavior of `selectionColor` the cursor color will be set independently diff --git a/packages/react-native/Libraries/Components/TextInput/TextInput.js b/packages/react-native/Libraries/Components/TextInput/TextInput.js index b56c388d88c9b4..f95bec49f9a4cf 100644 --- a/packages/react-native/Libraries/Components/TextInput/TextInput.js +++ b/packages/react-native/Libraries/Components/TextInput/TextInput.js @@ -741,6 +741,7 @@ function InternalTextInput(props: TextInputProps): React.Node { accessibilityState={_accessibilityState} accessibilityLabelledBy={_accessibilityLabelledBy} accessible={accessible} + acceptDragAndDropTypes={props.experimental_acceptDragAndDropTypes} autoCapitalize={autoCapitalize} submitBehavior={submitBehavior} caretHidden={caretHidden} diff --git a/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap b/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap index d64601d1560022..aeefeec68c2d40 100644 --- a/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap +++ b/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap @@ -2831,6 +2831,7 @@ export type TextInputIOSProps = $ReadOnly<{ smartInsertDelete?: ?boolean, }>; export type TextInputAndroidProps = $ReadOnly<{ + experimental_acceptDragAndDropTypes?: ?$ReadOnlyArray, cursorColor?: ?ColorValue, selectionHandleColor?: ?ColorValue, disableFullscreenUI?: ?boolean, diff --git a/packages/react-native/ReactAndroid/api/ReactAndroid.api b/packages/react-native/ReactAndroid/api/ReactAndroid.api index 67a6a658e336ed..dd7804c781f99d 100644 --- a/packages/react-native/ReactAndroid/api/ReactAndroid.api +++ b/packages/react-native/ReactAndroid/api/ReactAndroid.api @@ -6650,6 +6650,7 @@ public class com/facebook/react/views/textinput/ReactEditText : androidx/appcomp public final fun getBorderColor (I)I protected final fun getContainsImages ()Z public final fun getDisableFullscreenUI ()Z + public final fun getDragAndDropFilter ()Ljava/util/List; protected final fun getNativeEventCount ()I public final fun getReturnKeyType ()Ljava/lang/String; public final fun getStagedInputType ()I @@ -6669,6 +6670,7 @@ public class com/facebook/react/views/textinput/ReactEditText : androidx/appcomp public fun onConfigurationChanged (Landroid/content/res/Configuration;)V public fun onCreateInputConnection (Landroid/view/inputmethod/EditorInfo;)Landroid/view/inputmethod/InputConnection; public fun onDetachedFromWindow ()V + public fun onDragEvent (Landroid/view/DragEvent;)Z public fun onDraw (Landroid/graphics/Canvas;)V public fun onFinishTemporaryDetach ()V protected fun onFocusChanged (ZILandroid/graphics/Rect;)V @@ -6694,6 +6696,7 @@ public class com/facebook/react/views/textinput/ReactEditText : androidx/appcomp public final fun setContentSizeWatcher (Lcom/facebook/react/views/textinput/ContentSizeWatcher;)V public final fun setContextMenuHidden (Z)V public final fun setDisableFullscreenUI (Z)V + public final fun setDragAndDropFilter (Ljava/util/List;)V public final fun setEventDispatcher (Lcom/facebook/react/uimanager/events/EventDispatcher;)V public final fun setFontFamily (Ljava/lang/String;)V public fun setFontFeatureSettings (Ljava/lang/String;)V @@ -6757,6 +6760,7 @@ public class com/facebook/react/views/textinput/ReactTextInputManager : com/face public synthetic fun receiveCommand (Landroid/view/View;Ljava/lang/String;Lcom/facebook/react/bridge/ReadableArray;)V public fun receiveCommand (Lcom/facebook/react/views/textinput/ReactEditText;ILcom/facebook/react/bridge/ReadableArray;)V public fun receiveCommand (Lcom/facebook/react/views/textinput/ReactEditText;Ljava/lang/String;Lcom/facebook/react/bridge/ReadableArray;)V + public final fun setAcceptDragAndDropTypes (Lcom/facebook/react/views/textinput/ReactEditText;Lcom/facebook/react/bridge/ReadableArray;)V public final fun setAllowFontScaling (Lcom/facebook/react/views/textinput/ReactEditText;Z)V public final fun setAutoCapitalize (Lcom/facebook/react/views/textinput/ReactEditText;Lcom/facebook/react/bridge/Dynamic;)V public final fun setAutoCorrect (Lcom/facebook/react/views/textinput/ReactEditText;Ljava/lang/Boolean;)V diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt index 3c9e4cbba28dc1..2936dd005c8c2a 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt @@ -28,6 +28,7 @@ import android.text.method.KeyListener import android.text.method.QwertyKeyListener import android.util.TypedValue import android.view.ActionMode +import android.view.DragEvent import android.view.Gravity import android.view.KeyEvent import android.view.Menu @@ -121,6 +122,7 @@ public open class ReactEditText public constructor(context: Context) : AppCompat public var stagedInputType: Int protected var containsImages: Boolean = false public var submitBehavior: String? = null + public var dragAndDropFilter: List? = null private var disableFullscreen: Boolean private var selectionWatcher: SelectionWatcher? = null @@ -1192,6 +1194,17 @@ public open class ReactEditText public constructor(context: Context) : AppCompat super.onDraw(canvas) } + public override fun onDragEvent(event: DragEvent): Boolean { + val dragFilter = dragAndDropFilter + if (dragFilter != null && event.action == DragEvent.ACTION_DRAG_STARTED) { + val shouldHandle = dragFilter.any { filter -> event.clipDescription.hasMimeType(filter) } + if (!shouldHandle) { + return false + } + } + return super.onDragEvent(event) + } + /** * This class will redirect *TextChanged calls to the listeners only in the case where the text is * changed by the user, and not explicitly set by JS. diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.kt index cc0a42197f1b21..373f6c673512fa 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.kt @@ -770,6 +770,22 @@ public open class ReactTextInputManager public constructor() : view.returnKeyType = returnKeyType } + @ReactProp(name = "acceptDragAndDropTypes") + public fun setAcceptDragAndDropTypes( + view: ReactEditText, + acceptDragAndDropTypes: ReadableArray? + ) { + if (acceptDragAndDropTypes == null) { + view.dragAndDropFilter = null + } else { + val acceptedTypes = mutableListOf() + for (i in 0 until acceptDragAndDropTypes.size()) { + acceptDragAndDropTypes.getString(i)?.also(acceptedTypes::add) + } + view.dragAndDropFilter = acceptedTypes + } + } + @ReactProp(name = "disableFullscreenUI", defaultBoolean = false) public fun setDisableFullscreenUI(view: ReactEditText, disableFullscreenUI: Boolean) { view.disableFullscreenUI = disableFullscreenUI diff --git a/packages/rn-tester/js/examples/TextInput/TextInputExample.android.js b/packages/rn-tester/js/examples/TextInput/TextInputExample.android.js index 948635ff940109..551e4277ce7b92 100644 --- a/packages/rn-tester/js/examples/TextInput/TextInputExample.android.js +++ b/packages/rn-tester/js/examples/TextInput/TextInputExample.android.js @@ -448,6 +448,27 @@ const examples: Array = [ return ; }, }, + { + title: 'Drag and drop', + render: function (): React.Node { + return ( + + + + + + ); + }, + }, ]; module.exports = ({