diff --git a/android/src/main/java/com/swmansion/enriched/textinput/EnrichedTextInputView.kt b/android/src/main/java/com/swmansion/enriched/textinput/EnrichedTextInputView.kt index 023cc20fc..efabb2dd2 100644 --- a/android/src/main/java/com/swmansion/enriched/textinput/EnrichedTextInputView.kt +++ b/android/src/main/java/com/swmansion/enriched/textinput/EnrichedTextInputView.kt @@ -1005,6 +1005,23 @@ class EnrichedTextInputView : selection?.validateStyles() } + fun deleteAtSelection() { + val inputConnection = onCreateInputConnection(EditorInfo()) + + if (inputConnection != null) { + val start = selectionStart.coerceAtLeast(0) + val end = selectionEnd.coerceAtLeast(0) + + if (start != end) { + // If we have selection - delete it + inputConnection.commitText("", 1) + } else { + // If we don't have selection - delete previous character + inputConnection.deleteSurroundingText(1, 0) + } + } + } + fun requestHTML(requestId: Int) { val html = try { diff --git a/android/src/main/java/com/swmansion/enriched/textinput/EnrichedTextInputViewManager.kt b/android/src/main/java/com/swmansion/enriched/textinput/EnrichedTextInputViewManager.kt index 9dcbb8244..f1b7775c0 100644 --- a/android/src/main/java/com/swmansion/enriched/textinput/EnrichedTextInputViewManager.kt +++ b/android/src/main/java/com/swmansion/enriched/textinput/EnrichedTextInputViewManager.kt @@ -479,6 +479,10 @@ class EnrichedTextInputViewManager : view?.setTextAlignment(alignment) } + override fun deleteAtSelection(view: EnrichedTextInputView?) { + view?.deleteAtSelection() + } + override fun measure( context: Context, localData: ReadableMap?, diff --git a/ios/EnrichedTextInputView.mm b/ios/EnrichedTextInputView.mm index a899aa629..50714641d 100644 --- a/ios/EnrichedTextInputView.mm +++ b/ios/EnrichedTextInputView.mm @@ -1296,6 +1296,8 @@ - (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args { if (!_placeholderLabel.isHidden) { [self refreshPlaceholderLabelStyles]; } + } else if ([commandName isEqualToString:@"deleteAtSelection"]) { + [self deleteAtSelection]; } } @@ -1335,6 +1337,27 @@ - (void)setValue:(NSString *)value { [self anyTextMayHaveBeenModified]; } +- (void)deleteAtSelection { + NSRange range = textView.selectedRange; + + // Checking if there is anything to delete + if (range.location > 0 || range.length > 0) { + // If we have no selection - we want to manually set range + // to cover the character before the caret + if (range.length == 0) { + range.location -= 1; + range.length = 1; + } + + // This imitates delete button on keyboard press + if ([textView.delegate textView:textView + shouldChangeTextInRange:range + replacementText:@""]) { + [textView deleteBackward]; + } + } +} + - (void)setCustomSelection:(NSInteger)visibleStart end:(NSInteger)visibleEnd { NSString *text = textView.textStorage.string; diff --git a/src/native/EnrichedTextInput.tsx b/src/native/EnrichedTextInput.tsx index feffab4cc..e339360a3 100644 --- a/src/native/EnrichedTextInput.tsx +++ b/src/native/EnrichedTextInput.tsx @@ -277,6 +277,9 @@ export const EnrichedTextInput = ({ ) => { Commands.setTextAlignment(nullthrows(nativeRef.current), alignment); }, + deleteAtSelection: () => { + Commands.deleteAtSelection(nullthrows(nativeRef.current)); + }, })); const handleMentionEvent = (e: NativeSyntheticEvent) => { diff --git a/src/spec/EnrichedTextInputNativeComponent.ts b/src/spec/EnrichedTextInputNativeComponent.ts index 20e9d12b4..6044babd1 100644 --- a/src/spec/EnrichedTextInputNativeComponent.ts +++ b/src/spec/EnrichedTextInputNativeComponent.ts @@ -482,6 +482,7 @@ interface NativeCommands { viewRef: React.ElementRef, alignment: string ) => void; + deleteAtSelection: (viewRef: React.ElementRef) => void; } export const Commands: NativeCommands = codegenNativeCommands({ @@ -516,6 +517,7 @@ export const Commands: NativeCommands = codegenNativeCommands({ 'addMention', 'requestHTML', 'setTextAlignment', + 'deleteAtSelection', ], }); diff --git a/src/types.ts b/src/types.ts index acda85b41..75c5b62e8 100644 --- a/src/types.ts +++ b/src/types.ts @@ -564,6 +564,12 @@ export interface EnrichedTextInputInstance extends NativeMethods { setTextAlignment: ( alignment: 'left' | 'center' | 'right' | 'justify' | 'auto' ) => void; + + /** + * Deletes text at current selection. If there is no selection - deletes one character + * backwards. + */ + deleteAtSelection: () => void; } export interface ContextMenuItem { diff --git a/src/web/EnrichedTextInput.tsx b/src/web/EnrichedTextInput.tsx index 8ec53d0d7..97ebd04a9 100644 --- a/src/web/EnrichedTextInput.tsx +++ b/src/web/EnrichedTextInput.tsx @@ -376,6 +376,28 @@ export const EnrichedTextInput = ({ runFocused(editor, (c) => c.setTextAlign(alignment)); } }, + deleteAtSelection: () => { + runFocused(editor, (c) => { + const { from, empty, $from } = editor.state.selection; + + // If have selection - we delete it + if (!empty) { + return c.deleteSelection(); + } + + const isAtBlockStart = $from.parentOffset === 0; + + if (isAtBlockStart) { + // If caret is in the beginning of the line - we join two lines together + return c.joinBackward(); + } else if (from > 1) { + // If caret is not in the beginning of the line - we delete previous character + return c.deleteRange({ from: from - 1, to: from }); + } + + return c.focus(); + }); + }, }), [editor, mentionIndicatorsRef, useHtmlNormalizerRef] );