diff --git a/android/src/main/java/com/typerich/TypeRichTextInputView.kt b/android/src/main/java/com/typerich/TypeRichTextInputView.kt index 0f49819..808a731 100644 --- a/android/src/main/java/com/typerich/TypeRichTextInputView.kt +++ b/android/src/main/java/com/typerich/TypeRichTextInputView.kt @@ -64,6 +64,7 @@ class TypeRichTextInputView : AppCompatEditText { private var lineHeightPx: Int? = null private var isSettingTextFromJS = false private var isInitialized = false + private var disableImagePasting = false constructor(context: Context) : super(context) { prepareComponent() @@ -140,23 +141,34 @@ class TypeRichTextInputView : AppCompatEditText { override fun onCreateInputConnection(outAttrs: EditorInfo): InputConnection? { val ic = super.onCreateInputConnection(outAttrs) ?: return null - EditorInfoCompat.setContentMimeTypes( - outAttrs, - arrayOf("image/png", "image/jpg", "image/jpeg", "image/gif", "image/webp") - ) + if (!disableImagePasting) { + EditorInfoCompat.setContentMimeTypes( + outAttrs, + arrayOf("image/png", "image/jpg", "image/jpeg", "image/gif", "image/webp") + ) + + return InputConnectionCompat.createWrapper(ic, outAttrs, onCommitContent) + } - return InputConnectionCompat.createWrapper(ic, outAttrs, onCommitContent) + return ic } private val onCommitContent = InputConnectionCompat.OnCommitContentListener { info, flags, _ -> try { - // request permission if needed - if ((flags and InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0) { + val hasPermission = + (flags and InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0 + + if (hasPermission) { try { info.requestPermission() - } catch (ex: Exception) { - // permission failed + } catch (_: Exception) {} + } + + if (disableImagePasting) { + if (hasPermission) { + try { info.releasePermission() } catch (_: Exception) {} } + return@OnCommitContentListener false } val uri = info.contentUri @@ -189,7 +201,7 @@ class TypeRichTextInputView : AppCompatEditText { } } - // paste handler + // context menu paste handler override fun onTextContextMenuItem(id: Int): Boolean { if (id == android.R.id.paste || id == android.R.id.pasteAsPlainText) { val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as? ClipboardManager @@ -198,6 +210,12 @@ class TypeRichTextInputView : AppCompatEditText { val clip = clipboard.primaryClip ?: return super.onTextContextMenuItem(id) val item = clip.getItemAt(0) + if (disableImagePasting) { + if (item.uri != null || item.intent?.data != null) { + return true + } + } + // uri item.uri?.let { uri -> val source = EnumPasteSource.CLIPBOARD.value @@ -577,6 +595,10 @@ class TypeRichTextInputView : AppCompatEditText { } } + fun setDisableImagePasting(disabled: Boolean){ + this.disableImagePasting = disabled + } + override fun isLayoutRequested(): Boolean { return false } diff --git a/android/src/main/java/com/typerich/TypeRichTextInputViewManager.kt b/android/src/main/java/com/typerich/TypeRichTextInputViewManager.kt index ee9ae94..c5c076c 100644 --- a/android/src/main/java/com/typerich/TypeRichTextInputViewManager.kt +++ b/android/src/main/java/com/typerich/TypeRichTextInputViewManager.kt @@ -145,6 +145,11 @@ class TypeRichTextInputViewManager : view?.setLineHeightReact(lineHeight) } + @ReactProp(name = "disableImagePasting") + override fun setDisableImagePasting(view: TypeRichTextInputView?, value: Boolean) { + view?.setDisableImagePasting(value) + } + override fun onAfterUpdateTransaction(view: TypeRichTextInputView) { super.onAfterUpdateTransaction(view) view.afterUpdateTransaction() diff --git a/example/src/App.tsx b/example/src/App.tsx index 868d9b3..9d1f9ea 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -180,6 +180,7 @@ export default function App() { fontWeight={'200'} fontSize={24} color="indigo" + disableImagePasting={false} /> disableImagePasting) { + _disableImagePasting = newProps.disableImagePasting; + } + #pragma mark - Style Props // Text color @@ -815,4 +825,7 @@ - (void)dispatchSelectionChangeIfNeeded { // return _isHandlingUserInput; //} +- (BOOL)isDisableImagePasting{ + return _disableImagePasting; +} @end diff --git a/ios/inputTextView/TypeRichUITextView.mm b/ios/inputTextView/TypeRichUITextView.mm index 4d74565..8256675 100644 --- a/ios/inputTextView/TypeRichUITextView.mm +++ b/ios/inputTextView/TypeRichUITextView.mm @@ -13,7 +13,17 @@ @implementation TypeRichUITextView - (void)paste:(id)sender { UIPasteboard *pb = UIPasteboard.generalPasteboard; - if (pb.hasImages) { + if ([self.owner isDisableImagePasting] && + pb.hasImages && + !pb.hasStrings) { + return; + } + + if ( + ![self.owner isDisableImagePasting] + && pb.hasImages + ) { + UIImage *image = pb.image; if (!image) { [super paste:sender]; @@ -53,7 +63,11 @@ - (void)paste:(id)sender { - (BOOL)canPasteItemProviders:(NSArray *)itemProviders { for (NSItemProvider *provider in itemProviders) { - if ([provider hasItemConformingToTypeIdentifier:@"public.text"] || + if ([provider hasItemConformingToTypeIdentifier:@"public.text"]) { + return YES; + } + + if (![self.owner isDisableImagePasting] && [provider hasItemConformingToTypeIdentifier:@"public.image"]) { return YES; } @@ -65,6 +79,13 @@ - (BOOL)canPerformAction:(SEL)action withSender:(id)sender { if (action == @selector(paste:)) { UIPasteboard *pb = UIPasteboard.generalPasteboard; + if ( + [self.owner isDisableImagePasting] && + pb.hasImages && + !pb.hasStrings) { + return NO; + } + // Allow paste if there is text OR image if (pb.hasStrings || pb.hasImages) { return YES; diff --git a/src/TypeRichTextInput.tsx b/src/TypeRichTextInput.tsx index 8dcc6f9..4df3863 100644 --- a/src/TypeRichTextInput.tsx +++ b/src/TypeRichTextInput.tsx @@ -28,7 +28,7 @@ export function normalizeEvent(event: MaybeNativeEvent): T { return event as T; } -// Public facing props (same as NativeProps but events normalized) +// normalised events export interface TypeRichTextInputProps extends Omit< TypeRichTextInputNativeProps, @@ -38,7 +38,6 @@ export interface TypeRichTextInputProps | 'onInputBlur' | 'onPasteImage' > { - // JS-friendly callbacks onFocus?: () => void; onBlur?: () => void; onChangeText?: (value: string) => void; @@ -67,8 +66,7 @@ export interface TypeRichTextInputRef { * - Fabric-based rendering * - custom ShadowNode on Android * - * iOS support is currently unavailable and renders a `View` comp as fallback - * we are planning to add support for ios too soon + * iOS support is currently in Beta Stage and */ const TypeRichTextInput = forwardRef( (props: TypeRichTextInputProps, ref: Ref) => { diff --git a/src/TypeRichTextInputNativeComponent.ts b/src/TypeRichTextInputNativeComponent.ts index 1336f13..a4f9ca9 100644 --- a/src/TypeRichTextInputNativeComponent.ts +++ b/src/TypeRichTextInputNativeComponent.ts @@ -50,7 +50,7 @@ export interface TypeRichTextInputNativeProps extends ViewProps { keyboardAppearance?: WithDefault<'default' | 'light' | 'dark', 'default'>; // ios only // Todo - // disableImagePasting?: boolean + disableImagePasting?: boolean; // event callbacks onInputFocus?: DirectEventHandler;