From be538d3b59bdc9574a9c4e2711e50d4210e3446b Mon Sep 17 00:00:00 2001 From: Ahmed Haracic Date: Mon, 8 Dec 2025 17:52:34 +0100 Subject: [PATCH 1/6] feat: add imperative html method --- .../enriched/EnrichedTextInputViewManager.kt | 19 +++++++++++++ .../events/OnRequestHtmlResultEvent.kt | 28 +++++++++++++++++++ docs/API_REFERENCE.md | 8 ++++++ ios/EnrichedTextInputView.mm | 16 ++++++++++- src/EnrichedTextInput.tsx | 24 ++++++++++++++++ src/EnrichedTextInputNativeComponent.ts | 11 ++++++++ 6 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 android/src/main/java/com/swmansion/enriched/events/OnRequestHtmlResultEvent.kt diff --git a/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewManager.kt b/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewManager.kt index b31b8d4ac..e074029a6 100644 --- a/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewManager.kt +++ b/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewManager.kt @@ -24,6 +24,8 @@ import com.swmansion.enriched.events.OnInputFocusEvent import com.swmansion.enriched.events.OnLinkDetectedEvent import com.swmansion.enriched.events.OnMentionDetectedEvent import com.swmansion.enriched.events.OnMentionEvent +import com.swmansion.enriched.events.OnRequestHtmlResultEvent +import com.swmansion.enriched.utils.EnrichedParser import com.swmansion.enriched.spans.EnrichedSpans import com.swmansion.enriched.styles.HtmlStyle import com.swmansion.enriched.utils.jsonStringToStringMap @@ -71,6 +73,7 @@ class EnrichedTextInputViewManager : SimpleViewManager(), map.put(OnMentionDetectedEvent.EVENT_NAME, mapOf("registrationName" to OnMentionDetectedEvent.EVENT_NAME)) map.put(OnMentionEvent.EVENT_NAME, mapOf("registrationName" to OnMentionEvent.EVENT_NAME)) map.put(OnChangeSelectionEvent.EVENT_NAME, mapOf("registrationName" to OnChangeSelectionEvent.EVENT_NAME)) + map.put(OnRequestHtmlResultEvent.EVENT_NAME, mapOf("registrationName" to OnRequestHtmlResultEvent.EVENT_NAME)) return map } @@ -268,6 +271,22 @@ class EnrichedTextInputViewManager : SimpleViewManager(), view?.addMention(text, indicator, attributes) } + override fun requestHTML(view: EnrichedTextInputView?, requestId: Int) { + if (view == null) return + + val spannable = view.text as? android.text.Spannable + val html = if (spannable != null) { + EnrichedParser.toHtml(spannable) + } else { + "\n

\n" + } + + val context = view.context as com.facebook.react.bridge.ReactContext + val surfaceId = UIManagerHelper.getSurfaceId(context) + val dispatcher = UIManagerHelper.getEventDispatcherForReactTag(context, view.id) + dispatcher?.dispatchEvent(OnRequestHtmlResultEvent(surfaceId, view.id, requestId, html)) + } + override fun measure( context: Context, localData: ReadableMap?, diff --git a/android/src/main/java/com/swmansion/enriched/events/OnRequestHtmlResultEvent.kt b/android/src/main/java/com/swmansion/enriched/events/OnRequestHtmlResultEvent.kt new file mode 100644 index 000000000..f8710315f --- /dev/null +++ b/android/src/main/java/com/swmansion/enriched/events/OnRequestHtmlResultEvent.kt @@ -0,0 +1,28 @@ +package com.swmansion.enriched.events + +import com.facebook.react.bridge.Arguments +import com.facebook.react.bridge.WritableMap +import com.facebook.react.uimanager.events.Event + +class OnRequestHtmlResultEvent( + surfaceId: Int, + viewId: Int, + private val requestId: Int, + private val html: String +) : Event(surfaceId, viewId) { + + override fun getEventName(): String { + return EVENT_NAME + } + + override fun getEventData(): WritableMap { + val eventData: WritableMap = Arguments.createMap() + eventData.putInt("requestId", requestId) + eventData.putString("html", html) + return eventData + } + + companion object { + const val EVENT_NAME: String = "onRequestHtmlResult" + } +} diff --git a/docs/API_REFERENCE.md b/docs/API_REFERENCE.md index 106f79013..d7f9a9a15 100644 --- a/docs/API_REFERENCE.md +++ b/docs/API_REFERENCE.md @@ -333,6 +333,14 @@ focus: () => void; Focuses the input. +### `.getHTML()` + +```ts +getHTML: () => Promise; +``` + +Returns a Promise that resolves with the current HTML content of the input. This is useful when you need to get the HTML on-demand (e.g., when saving) without the performance overhead of continuous HTML parsing via `onChangeHtml`. + ### `.setImage()` > [!NOTE] diff --git a/ios/EnrichedTextInputView.mm b/ios/EnrichedTextInputView.mm index 2e3770b9e..463d3eb18 100644 --- a/ios/EnrichedTextInputView.mm +++ b/ios/EnrichedTextInputView.mm @@ -800,8 +800,11 @@ - (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args { NSString *uri = (NSString *)args[0]; CGFloat imgWidth = [(NSNumber*)args[1] floatValue]; CGFloat imgHeight = [(NSNumber*)args[2] floatValue]; - + [self addImage:uri width:imgWidth height:imgHeight]; + } else if([commandName isEqualToString:@"requestHTML"]) { + NSInteger requestId = [((NSNumber*)args[0]) integerValue]; + [self requestHTML:requestId]; } } @@ -903,6 +906,17 @@ - (void)tryEmittingOnChangeHtmlEvent { } } +- (void)requestHTML:(NSInteger)requestId { + auto emitter = [self getEventEmitter]; + if(emitter != nullptr) { + NSString *htmlOutput = [parser parseToHtmlFromRange:NSMakeRange(0, textView.textStorage.string.length)]; + emitter->onRequestHtmlResult({ + .requestId = static_cast(requestId), + .html = [htmlOutput toCppString] + }); + } +} + // MARK: - Styles manipulation - (void)toggleRegularStyle:(StyleType)type { diff --git a/src/EnrichedTextInput.tsx b/src/EnrichedTextInput.tsx index c2202c679..797e62bbe 100644 --- a/src/EnrichedTextInput.tsx +++ b/src/EnrichedTextInput.tsx @@ -16,6 +16,7 @@ import EnrichedTextInputNativeComponent, { type OnMentionEvent, type OnMentionDetected, type OnMentionDetectedInternal, + type OnRequestHtmlResultEvent, type MentionStyleProperties, } from './EnrichedTextInputNativeComponent'; import type { @@ -37,6 +38,7 @@ export interface EnrichedTextInputInstance extends NativeMethods { focus: () => void; blur: () => void; setValue: (value: string) => void; + getHTML: () => Promise; // Text formatting commands toggleBold: () => void; @@ -162,6 +164,9 @@ const warnAboutMissconfiguredMentions = (indicator: string) => { ); }; +let nextRequestId = 1; +const pendingHtmlRequests = new Map void>(); + type ComponentType = (Component & NativeMethods) | null; export const EnrichedTextInput = ({ @@ -229,6 +234,13 @@ export const EnrichedTextInput = ({ setValue: (value: string) => { Commands.setValue(nullthrows(nativeRef.current), value); }, + getHTML: () => { + return new Promise((resolve) => { + const requestId = nextRequestId++; + pendingHtmlRequests.set(requestId, resolve); + Commands.requestHTML(nullthrows(nativeRef.current), requestId); + }); + }, toggleBold: () => { Commands.toggleBold(nullthrows(nativeRef.current)); }, @@ -323,6 +335,17 @@ export const EnrichedTextInput = ({ onMentionDetected?.({ text, indicator, attributes }); }; + const handleRequestHtmlResult = ( + e: NativeSyntheticEvent + ) => { + const { requestId, html } = e.nativeEvent; + const resolve = pendingHtmlRequests.get(requestId); + if (resolve) { + pendingHtmlRequests.delete(requestId); + resolve(html); + } + }; + return ( ; onMention?: DirectEventHandler; onChangeSelection?: DirectEventHandler; + onRequestHtmlResult?: DirectEventHandler; // Style related props - used for generating proper setters in component's manager // These should not be passed as regular props @@ -203,6 +209,10 @@ interface NativeCommands { text: string, payload: string ) => void; + requestHTML: ( + viewRef: React.ElementRef, + requestId: Int32 + ) => void; } export const Commands: NativeCommands = codegenNativeCommands({ @@ -229,6 +239,7 @@ export const Commands: NativeCommands = codegenNativeCommands({ 'addImage', 'startMention', 'addMention', + 'requestHTML', ], }); From 088b596e021b50f865fa4ed3e332bbbb5998b22e Mon Sep 17 00:00:00 2001 From: Ahmed Haracic Date: Tue, 9 Dec 2025 08:33:44 +0100 Subject: [PATCH 2/6] fix: android missing import --- .../java/com/swmansion/enriched/EnrichedTextInputViewManager.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewManager.kt b/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewManager.kt index e074029a6..dd5e181ea 100644 --- a/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewManager.kt +++ b/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewManager.kt @@ -11,6 +11,7 @@ import com.facebook.react.uimanager.ThemedReactContext import com.facebook.react.uimanager.ViewDefaults import com.facebook.react.uimanager.ViewManagerDelegate import com.facebook.react.uimanager.ViewProps +import com.facebook.react.uimanager.UIManagerHelper import com.facebook.react.uimanager.annotations.ReactProp import com.facebook.react.viewmanagers.EnrichedTextInputViewManagerDelegate import com.facebook.react.viewmanagers.EnrichedTextInputViewManagerInterface From 953f61927075f9fc33c6561e006e11d202396887 Mon Sep 17 00:00:00 2001 From: Ahmed Haracic Date: Sun, 14 Dec 2025 19:02:34 +0100 Subject: [PATCH 3/6] Update src/EnrichedTextInput.tsx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Mikołaj Szydłowski <9szydlowski9@gmail.com> --- src/EnrichedTextInput.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EnrichedTextInput.tsx b/src/EnrichedTextInput.tsx index 797e62bbe..886e38367 100644 --- a/src/EnrichedTextInput.tsx +++ b/src/EnrichedTextInput.tsx @@ -164,7 +164,7 @@ const warnAboutMissconfiguredMentions = (indicator: string) => { ); }; -let nextRequestId = 1; +let nextHtmlRequestId = 1; const pendingHtmlRequests = new Map void>(); type ComponentType = (Component & NativeMethods) | null; From 7fbb8111ff981eefc7b2bf2fd0ba271f9bbbe53b Mon Sep 17 00:00:00 2001 From: Ahmed Haracic Date: Fri, 12 Dec 2025 11:24:36 +0100 Subject: [PATCH 4/6] feat: implement suggested fixes for getHTML method --- .../enriched/EnrichedTextInputView.kt | 14 +++++++ .../enriched/EnrichedTextInputViewManager.kt | 17 +------- .../events/OnRequestHtmlResultEvent.kt | 15 ++++--- .../enriched/utils/EnrichedParser.java | 8 ++++ ios/EnrichedTextInputView.mm | 23 +++++++---- src/EnrichedTextInput.tsx | 39 ++++++++++++++----- src/EnrichedTextInputNativeComponent.ts | 2 +- 7 files changed, 78 insertions(+), 40 deletions(-) diff --git a/android/src/main/java/com/swmansion/enriched/EnrichedTextInputView.kt b/android/src/main/java/com/swmansion/enriched/EnrichedTextInputView.kt index f6ed05a7f..de66e337b 100644 --- a/android/src/main/java/com/swmansion/enriched/EnrichedTextInputView.kt +++ b/android/src/main/java/com/swmansion/enriched/EnrichedTextInputView.kt @@ -29,6 +29,7 @@ import com.facebook.react.views.text.ReactTypefaceUtils.parseFontWeight import com.swmansion.enriched.events.MentionHandler import com.swmansion.enriched.events.OnInputBlurEvent import com.swmansion.enriched.events.OnInputFocusEvent +import com.swmansion.enriched.events.OnRequestHtmlResultEvent import com.swmansion.enriched.spans.EnrichedImageSpan import com.swmansion.enriched.spans.EnrichedSpans import com.swmansion.enriched.styles.InlineStyles @@ -566,6 +567,19 @@ class EnrichedTextInputView : AppCompatEditText { parametrizedStyles?.setMentionSpan(text, indicator, attributes) } + fun requestHTML(requestId: Int) { + val html = try { + EnrichedParser.toHtmlWithDefault(text) + } catch (e: Exception) { + null + } + + val reactContext = context as ReactContext + val surfaceId = UIManagerHelper.getSurfaceId(reactContext) + val dispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, id) + dispatcher?.dispatchEvent(OnRequestHtmlResultEvent(surfaceId, id, requestId, html, experimentalSynchronousEvents)) + } + // Sometimes setting up style triggers many changes in sequence // Eg. removing conflicting styles -> changing text -> applying spans // In such scenario we want to prevent from handling side effects (eg. onTextChanged) diff --git a/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewManager.kt b/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewManager.kt index dd5e181ea..5f1b1ee6a 100644 --- a/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewManager.kt +++ b/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewManager.kt @@ -11,7 +11,6 @@ import com.facebook.react.uimanager.ThemedReactContext import com.facebook.react.uimanager.ViewDefaults import com.facebook.react.uimanager.ViewManagerDelegate import com.facebook.react.uimanager.ViewProps -import com.facebook.react.uimanager.UIManagerHelper import com.facebook.react.uimanager.annotations.ReactProp import com.facebook.react.viewmanagers.EnrichedTextInputViewManagerDelegate import com.facebook.react.viewmanagers.EnrichedTextInputViewManagerInterface @@ -25,8 +24,6 @@ import com.swmansion.enriched.events.OnInputFocusEvent import com.swmansion.enriched.events.OnLinkDetectedEvent import com.swmansion.enriched.events.OnMentionDetectedEvent import com.swmansion.enriched.events.OnMentionEvent -import com.swmansion.enriched.events.OnRequestHtmlResultEvent -import com.swmansion.enriched.utils.EnrichedParser import com.swmansion.enriched.spans.EnrichedSpans import com.swmansion.enriched.styles.HtmlStyle import com.swmansion.enriched.utils.jsonStringToStringMap @@ -273,19 +270,7 @@ class EnrichedTextInputViewManager : SimpleViewManager(), } override fun requestHTML(view: EnrichedTextInputView?, requestId: Int) { - if (view == null) return - - val spannable = view.text as? android.text.Spannable - val html = if (spannable != null) { - EnrichedParser.toHtml(spannable) - } else { - "\n

\n" - } - - val context = view.context as com.facebook.react.bridge.ReactContext - val surfaceId = UIManagerHelper.getSurfaceId(context) - val dispatcher = UIManagerHelper.getEventDispatcherForReactTag(context, view.id) - dispatcher?.dispatchEvent(OnRequestHtmlResultEvent(surfaceId, view.id, requestId, html)) + view?.requestHTML(requestId) } override fun measure( diff --git a/android/src/main/java/com/swmansion/enriched/events/OnRequestHtmlResultEvent.kt b/android/src/main/java/com/swmansion/enriched/events/OnRequestHtmlResultEvent.kt index f8710315f..bda88e76b 100644 --- a/android/src/main/java/com/swmansion/enriched/events/OnRequestHtmlResultEvent.kt +++ b/android/src/main/java/com/swmansion/enriched/events/OnRequestHtmlResultEvent.kt @@ -8,20 +8,25 @@ class OnRequestHtmlResultEvent( surfaceId: Int, viewId: Int, private val requestId: Int, - private val html: String + private val html: String?, + private val experimentalSynchronousEvents: Boolean ) : Event(surfaceId, viewId) { - override fun getEventName(): String { - return EVENT_NAME - } + override fun getEventName(): String = EVENT_NAME override fun getEventData(): WritableMap { val eventData: WritableMap = Arguments.createMap() eventData.putInt("requestId", requestId) - eventData.putString("html", html) + if (html != null) { + eventData.putString("html", html) + } else { + eventData.putNull("html") + } return eventData } + override fun experimental_isSynchronous(): Boolean = experimentalSynchronousEvents + companion object { const val EVENT_NAME: String = "onRequestHtmlResult" } diff --git a/android/src/main/java/com/swmansion/enriched/utils/EnrichedParser.java b/android/src/main/java/com/swmansion/enriched/utils/EnrichedParser.java index d89885d5c..1b0758be7 100644 --- a/android/src/main/java/com/swmansion/enriched/utils/EnrichedParser.java +++ b/android/src/main/java/com/swmansion/enriched/utils/EnrichedParser.java @@ -105,6 +105,14 @@ public static String toHtml(Spanned text) { String normalizedBlockQuote = normalizedCodeBlock.replaceAll("\\n
", ""); return "\n" + normalizedBlockQuote + ""; } + + public static String toHtmlWithDefault(CharSequence text) { + if (text instanceof Spanned) { + return toHtml((Spanned) text); + } + return "\n

\n"; + } + /** * Returns an HTML escaped representation of the given plain text. */ diff --git a/ios/EnrichedTextInputView.mm b/ios/EnrichedTextInputView.mm index b82385142..8f0048bfe 100644 --- a/ios/EnrichedTextInputView.mm +++ b/ios/EnrichedTextInputView.mm @@ -974,8 +974,8 @@ - (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args { CGFloat imgHeight = [(NSNumber *)args[2] floatValue]; [self addImage:uri width:imgWidth height:imgHeight]; - } else if([commandName isEqualToString:@"requestHTML"]) { - NSInteger requestId = [((NSNumber*)args[0]) integerValue]; + } else if ([commandName isEqualToString:@"requestHTML"]) { + NSInteger requestId = [((NSNumber *)args[0]) integerValue]; [self requestHTML:requestId]; } } @@ -1077,12 +1077,19 @@ - (void)tryEmittingOnChangeHtmlEvent { - (void)requestHTML:(NSInteger)requestId { auto emitter = [self getEventEmitter]; - if(emitter != nullptr) { - NSString *htmlOutput = [parser parseToHtmlFromRange:NSMakeRange(0, textView.textStorage.string.length)]; - emitter->onRequestHtmlResult({ - .requestId = static_cast(requestId), - .html = [htmlOutput toCppString] - }); + if (emitter != nullptr) { + @try { + NSString *htmlOutput = [parser + parseToHtmlFromRange:NSMakeRange(0, + textView.textStorage.string.length)]; + emitter->onRequestHtmlResult({ + .requestId = static_cast(requestId), + .html = [htmlOutput toCppString]}); + } @catch (NSException *exception) { + emitter->onRequestHtmlResult({ + .requestId = static_cast(requestId), + .html = folly::dynamic(nullptr)}); + } } } diff --git a/src/EnrichedTextInput.tsx b/src/EnrichedTextInput.tsx index 886e38367..e643305be 100644 --- a/src/EnrichedTextInput.tsx +++ b/src/EnrichedTextInput.tsx @@ -1,6 +1,7 @@ import { type Component, type RefObject, + useEffect, useImperativeHandle, useMemo, useRef, @@ -164,9 +165,6 @@ const warnAboutMissconfiguredMentions = (indicator: string) => { ); }; -let nextHtmlRequestId = 1; -const pendingHtmlRequests = new Map void>(); - type ComponentType = (Component & NativeMethods) | null; export const EnrichedTextInput = ({ @@ -198,6 +196,23 @@ export const EnrichedTextInput = ({ ...rest }: EnrichedTextInputProps) => { const nativeRef = useRef(null); + const nextRequestIdRef = useRef(1); + const pendingHtmlRequestsRef = useRef( + new Map< + number, + { resolve: (html: string) => void; reject: (error: Error) => void } + >() + ); + + useEffect(() => { + const pendingRequests = pendingHtmlRequestsRef.current; + return () => { + pendingRequests.forEach(({ reject }) => { + reject(new Error('Component unmounted')); + }); + pendingRequests.clear(); + }; + }, []); const normalizedHtmlStyle = useMemo( () => normalizeHtmlStyle(htmlStyle, mentionIndicators), @@ -235,9 +250,9 @@ export const EnrichedTextInput = ({ Commands.setValue(nullthrows(nativeRef.current), value); }, getHTML: () => { - return new Promise((resolve) => { - const requestId = nextRequestId++; - pendingHtmlRequests.set(requestId, resolve); + return new Promise((resolve, reject) => { + const requestId = nextRequestIdRef.current++; + pendingHtmlRequestsRef.current.set(requestId, { resolve, reject }); Commands.requestHTML(nullthrows(nativeRef.current), requestId); }); }, @@ -339,10 +354,14 @@ export const EnrichedTextInput = ({ e: NativeSyntheticEvent ) => { const { requestId, html } = e.nativeEvent; - const resolve = pendingHtmlRequests.get(requestId); - if (resolve) { - pendingHtmlRequests.delete(requestId); - resolve(html); + const pending = pendingHtmlRequestsRef.current.get(requestId); + if (pending) { + pendingHtmlRequestsRef.current.delete(requestId); + if (html === null || typeof html !== 'string') { + pending.reject(new Error('Failed to parse HTML')); + } else { + pending.resolve(html); + } } }; diff --git a/src/EnrichedTextInputNativeComponent.ts b/src/EnrichedTextInputNativeComponent.ts index baa688db4..5bd119ca2 100644 --- a/src/EnrichedTextInputNativeComponent.ts +++ b/src/EnrichedTextInputNativeComponent.ts @@ -66,7 +66,7 @@ export interface OnChangeSelectionEvent { export interface OnRequestHtmlResultEvent { requestId: Int32; - html: string; + html: UnsafeMixed; } export interface MentionStyleProperties { From 9cbc6fcac2f0d2d16522f547ed1b7a8b4f2a2644 Mon Sep 17 00:00:00 2001 From: Igor Furgala Date: Mon, 15 Dec 2025 09:39:44 +0100 Subject: [PATCH 5/6] chore: tiny improvements, fix missing android import --- .../enriched/EnrichedTextInputViewManager.kt | 1 + src/EnrichedTextInput.tsx | 38 ++++++++++--------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewManager.kt b/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewManager.kt index 5f1b1ee6a..8c629cf5b 100644 --- a/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewManager.kt +++ b/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewManager.kt @@ -24,6 +24,7 @@ import com.swmansion.enriched.events.OnInputFocusEvent import com.swmansion.enriched.events.OnLinkDetectedEvent import com.swmansion.enriched.events.OnMentionDetectedEvent import com.swmansion.enriched.events.OnMentionEvent +import com.swmansion.enriched.events.OnRequestHtmlResultEvent import com.swmansion.enriched.spans.EnrichedSpans import com.swmansion.enriched.styles.HtmlStyle import com.swmansion.enriched.utils.jsonStringToStringMap diff --git a/src/EnrichedTextInput.tsx b/src/EnrichedTextInput.tsx index e643305be..22cc1f373 100644 --- a/src/EnrichedTextInput.tsx +++ b/src/EnrichedTextInput.tsx @@ -167,6 +167,11 @@ const warnAboutMissconfiguredMentions = (indicator: string) => { type ComponentType = (Component & NativeMethods) | null; +type HtmlRequest = { + resolve: (html: string) => void; + reject: (error: Error) => void; +}; + export const EnrichedTextInput = ({ ref, autoFocus, @@ -196,16 +201,12 @@ export const EnrichedTextInput = ({ ...rest }: EnrichedTextInputProps) => { const nativeRef = useRef(null); - const nextRequestIdRef = useRef(1); - const pendingHtmlRequestsRef = useRef( - new Map< - number, - { resolve: (html: string) => void; reject: (error: Error) => void } - >() - ); + + const nextHtmlRequestId = useRef(1); + const pendingHtmlRequests = useRef(new Map()); useEffect(() => { - const pendingRequests = pendingHtmlRequestsRef.current; + const pendingRequests = pendingHtmlRequests.current; return () => { pendingRequests.forEach(({ reject }) => { reject(new Error('Component unmounted')); @@ -251,8 +252,8 @@ export const EnrichedTextInput = ({ }, getHTML: () => { return new Promise((resolve, reject) => { - const requestId = nextRequestIdRef.current++; - pendingHtmlRequestsRef.current.set(requestId, { resolve, reject }); + const requestId = nextHtmlRequestId.current++; + pendingHtmlRequests.current.set(requestId, { resolve, reject }); Commands.requestHTML(nullthrows(nativeRef.current), requestId); }); }, @@ -354,15 +355,16 @@ export const EnrichedTextInput = ({ e: NativeSyntheticEvent ) => { const { requestId, html } = e.nativeEvent; - const pending = pendingHtmlRequestsRef.current.get(requestId); - if (pending) { - pendingHtmlRequestsRef.current.delete(requestId); - if (html === null || typeof html !== 'string') { - pending.reject(new Error('Failed to parse HTML')); - } else { - pending.resolve(html); - } + const pending = pendingHtmlRequests.current.get(requestId); + if (!pending) return; + + if (html === null || typeof html !== 'string') { + pending.reject(new Error('Failed to parse HTML')); + } else { + pending.resolve(html); } + + pendingHtmlRequests.current.delete(requestId); }; return ( From e50ff47a8eac1f08329d6127b5100847dc3e906e Mon Sep 17 00:00:00 2001 From: Igor Furgala Date: Mon, 15 Dec 2025 09:47:53 +0100 Subject: [PATCH 6/6] fix: lint clang --- ios/EnrichedTextInputView.mm | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/ios/EnrichedTextInputView.mm b/ios/EnrichedTextInputView.mm index 8f0048bfe..e1aaf9c01 100644 --- a/ios/EnrichedTextInputView.mm +++ b/ios/EnrichedTextInputView.mm @@ -1082,13 +1082,11 @@ - (void)requestHTML:(NSInteger)requestId { NSString *htmlOutput = [parser parseToHtmlFromRange:NSMakeRange(0, textView.textStorage.string.length)]; - emitter->onRequestHtmlResult({ - .requestId = static_cast(requestId), - .html = [htmlOutput toCppString]}); + emitter->onRequestHtmlResult({.requestId = static_cast(requestId), + .html = [htmlOutput toCppString]}); } @catch (NSException *exception) { - emitter->onRequestHtmlResult({ - .requestId = static_cast(requestId), - .html = folly::dynamic(nullptr)}); + emitter->onRequestHtmlResult({.requestId = static_cast(requestId), + .html = folly::dynamic(nullptr)}); } } }