Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
a801265
feat: add insertValue method
IslamRustamov Feb 1, 2026
7151d8d
fix: clamp start and end in insertValue
kacperzolkiewski Feb 10, 2026
ae3f3a2
Merge branch 'main' into feature/add-insert-text-method
kacperzolkiewski Feb 10, 2026
d54ccd5
fix: clamp start and end in insertValue on Android
kacperzolkiewski Feb 10, 2026
af3e5b6
Merge branch 'main' into feature/add-insert-text-method
kacperzolkiewski Mar 9, 2026
27cc3d5
Merge branch 'main' into feature/add-insert-text-method
kacperzolkiewski Mar 31, 2026
cd2cfa5
Merge branch 'main' into feature/add-insert-text-method
kacperzolkiewski Apr 2, 2026
8b6487b
fix: refactor inserting value
kacperzolkiewski Apr 2, 2026
e580611
Merge branch 'main' into feature/add-insert-text-method
kacperzolkiewski Jul 24, 2026
375e0f4
fix: inserting text into empty paragraph styled line
kacperzolkiewski Jul 27, 2026
1aee6c3
fix(android): inserting paragraph styles
kacperzolkiewski Jul 29, 2026
34fc2f1
fix: code review fixes
kacperzolkiewski Jul 29, 2026
5b46a8a
test: add e2e tests for insertValue
kacperzolkiewski Jul 29, 2026
dc6ef45
test: update screenshots for max test screen
kacperzolkiewski Jul 29, 2026
3f0bc33
docs: add insertValue description to api reference
kacperzolkiewski Jul 29, 2026
ebe9b00
feat(web): add support for insertValue
kacperzolkiewski Jul 31, 2026
6feacd3
test: add e2e web tests
kacperzolkiewski Jul 31, 2026
06f303f
Merge branch 'main' into feature/add-insert-text-method
kacperzolkiewski Jul 31, 2026
07568aa
test: update baseline
kacperzolkiewski Jul 31, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import android.graphics.Color
import android.graphics.Rect
import android.graphics.text.LineBreaker
import android.os.Build
import android.text.Editable
import android.text.InputType
import android.text.Spannable
import android.util.AttributeSet
Expand Down Expand Up @@ -359,6 +360,46 @@ class EnrichedTextInputView : AppCompatEditText {
setSelection(actualStart, actualEnd)
}

fun insertValue(
Comment thread
kacperzolkiewski marked this conversation as resolved.
value: String,
start: Int,
end: Int,
) {
val currentText = text as Editable

if (currentText.isEmpty()) {
setValue(value)
return
}

var safeStart = start.coerceAtLeast(0)
var safeEnd = end.coerceAtLeast(0)

val textLength = currentText.length
safeStart = safeStart.coerceAtMost(textLength)
safeEnd = safeEnd.coerceAtMost(textLength)

if (safeEnd < safeStart) {
return
}

runAsATransaction {
val newText = parseText(value)

currentText.replace(
safeStart,
safeEnd,
newText,
)

observeAsyncImages()

// Scroll to the last char of inserted text
val newCursorPos = (safeStart + newText.length).coerceAtMost(currentText.length)
setSelection(newCursorPos)
}
}

// Helper: Walks through the string skipping ZWSPs to find the Nth visible character
private fun getActualIndex(visibleIndex: Int): Int {
val currentText = text as Spannable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,15 @@ class EnrichedTextInputViewManager :
view?.setCustomSelection(start, end)
}

override fun insertValue(
view: EnrichedTextInputView?,
text: String,
start: Int,
end: Int,
) {
view?.insertValue(text, start, end)
}

override fun toggleBold(view: EnrichedTextInputView?) {
view?.verifyAndToggleStyle(EnrichedSpans.BOLD)
}
Expand Down
58 changes: 58 additions & 0 deletions ios/EnrichedTextInputView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -1282,6 +1282,12 @@ - (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args {
} else if ([commandName isEqualToString:@"requestHTML"]) {
NSInteger requestId = [((NSNumber *)args[0]) integerValue];
[self requestHTML:requestId];
} else if ([commandName isEqualToString:@"insertValue"]) {
NSString *text = (NSString *)args[0];
NSInteger start = [((NSNumber *)args[1]) integerValue];
NSInteger end = [((NSNumber *)args[2]) integerValue];

[self insertValue:text start:start end:end];
}
}

Expand Down Expand Up @@ -1328,6 +1334,58 @@ - (void)setCustomSelection:(NSInteger)visibleStart end:(NSInteger)visibleEnd {
textView.selectedRange = NSMakeRange(actualStart, actualEnd - actualStart);
}

- (void)insertValue:(NSString *)value
Comment thread
kacperzolkiewski marked this conversation as resolved.
start:(NSInteger)visibleStart
end:(NSInteger)visibleEnd {
if (value == nil) {
return;
}

NSString *currentText = textView.text;
NSInteger textLength = currentText.length;

if (textLength == 0) {
[self setValue:value];

return;
}

if (visibleStart < 0) {
visibleStart = 0;
}
if (visibleEnd < 0) {
visibleEnd = 0;
}

if (visibleStart > textLength) {
visibleStart = textLength;
}
if (visibleEnd > textLength) {
visibleEnd = textLength;
}

if (visibleEnd < visibleStart) {
return;
}

NSRange range = NSMakeRange(visibleStart, visibleEnd - visibleStart);

NSString *initiallyProcessedHtml = [parser initiallyProcessHtml:value];
if (initiallyProcessedHtml == nullptr) {
// just plain text
[textView.textStorage replaceCharactersInRange:range withString:value];

recentlyChangedRange = range;
textView.selectedRange = NSRange(range.location + value.length, 0);
} else {
// we've got some seemingly proper html
[parser replaceFromHtml:initiallyProcessedHtml range:range];
}

// set recentlyChangedRange and check for changes
[self anyTextMayHaveBeenModified];
}

// Helper: Walks through the string skipping ZWSPs to find the Nth visible
// character
- (NSUInteger)getActualIndex:(NSInteger)visibleIndex text:(NSString *)text {
Expand Down
4 changes: 4 additions & 0 deletions src/EnrichedTextInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export interface EnrichedTextInputInstance extends NativeMethods {
setValue: (value: string) => void;
setSelection: (start: number, end: number) => void;
getHTML: () => Promise<string>;
insertValue: (text: string, start: number, end: number) => void;

// Text formatting commands
toggleBold: () => void;
Expand Down Expand Up @@ -379,6 +380,9 @@ export const EnrichedTextInput = ({
setSelection: (start: number, end: number) => {
Commands.setSelection(nullthrows(nativeRef.current), start, end);
},
insertValue: (text, start, end) => {
Commands.insertValue(nullthrows(nativeRef.current), text, start, end);
},
}));

const handleMentionEvent = (e: NativeSyntheticEvent<OnMentionEvent>) => {
Expand Down
7 changes: 7 additions & 0 deletions src/spec/EnrichedTextInputNativeComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,12 @@ interface NativeCommands {
start: Int32,
end: Int32
) => void;
insertValue: (
viewRef: React.ElementRef<ComponentType>,
text: string,
start: Int32,
end: Int32
) => void;

// Text formatting commands
toggleBold: (viewRef: React.ElementRef<ComponentType>) => void;
Expand Down Expand Up @@ -469,6 +475,7 @@ export const Commands: NativeCommands = codegenNativeCommands<NativeCommands>({
'blur',
'setValue',
'setSelection',
'insertValue',

// Text formatting commands
'toggleBold',
Expand Down
Loading