Customized Input for GroupChannel is loosing focus repeatedly when trying to enter anything beyond a text length>1

So, we want to customize GroupChannelModule component Input, and the steps we followed to achieve our use-case are as follows:

We named Customized input component as CustomInput and replaced the module default Input by CustomInput.

const CustomGroupChannelModule = createGroupChannelModule({
      Input: CustomInput,
});

Our CustomInput code is as follows:

const CustomInput = ({
      SuggestedMentionList,
      shouldRenderInput,
      onPressSendUserMessage,
      onPressUpdateUserMessage,
      onPressUpdateFileMessage,
    }) => {
      const {
        channel,
        messageToEdit,
        setMessageToEdit,
        keyboardAvoidOffset = 0,
      } = useContext(GroupChannelContexts.Fragment);

      const chatAvailableState = getGroupChannelChatAvailableState(channel);

      return (
        <CustomChannelInput
          channel={channel}
          messageToEdit={messageToEdit}
          setMessageToEdit={setMessageToEdit}
          inputMuted={chatAvailableState.muted}
          inputFrozen={chatAvailableState.frozen}
          inputDisabled={chatAvailableState.disabled}
          keyboardAvoidOffset={keyboardAvoidOffset}
          shouldRenderInput={shouldRenderInput}
          onPressSendUserMessage={onPressSendUserMessage}
          onPressSendFileMessage={onPressSendFileMessage}
          onPressUpdateUserMessage={onPressUpdateUserMessage}
          onPressUpdateFileMessage={onPressUpdateFileMessage}
          SuggestedMentionList={SuggestedMentionList}
        />
      );
    };

Our CustomChannelInput component is below:

const CustomChannelInput = ({
        channel,
        messageToEdit,
        setMessageToEdit,
        inputMuted,
        inputFrozen,
        inputDisabled,
        keyboardAvoidOffset,
        shouldRenderInput,
        onPressSendUserMessage,
        onPressSendFileMessage,
        onPressUpdateUserMessage,
        onPressUpdateFileMessage,
        SuggestedMentionList,
      }) => {
        const GET_INPUT_KEY = (shouldReset) =>
          shouldReset ? "uikit-input-clear" : "uikit-input";

        const AUTO_FOCUS = Platform.select({
          ios: false,
          android: true,
          default: false,
        });

        const KEYBOARD_AVOID_VIEW_BEHAVIOR = Platform.select({
          ios: "padding",
          default: undefined,
        });

        const { top, left, right, bottom } = useSafeAreaInsets();
        const { features, mentionManager } = useSendbirdChat();

        const {
          selection,
          onSelectionChange,
          textInputRef,
          text,
          onChangeText,
          mentionedUsers,
        } = useMentionTextInput({
          messageToEdit,
        });

        const inputMode = useIIFE(() => {
          if (!messageToEdit) return "send";
          if (messageToEdit.isFileMessage()) return "send";
          return "edit";
        });

        const mentionAvailable =
          features.userMentionEnabled &&
          channel.isGroupChannel() &&
          !channel.isBroadcast;

        const inputKeyToRemount = GET_INPUT_KEY(
          mentionAvailable ? mentionedUsers.length === 0 : false
        );

        const [inputHeight, setInputHeight] = useState(
          styles.inputDefault.height
        );

        const useTypingTrigger = (text, channel) => {
          if (channel.isGroupChannel()) {
            useEffect(() => {
              if (text.length === 0) channel.endTyping();
              else channel.startTyping();
            }, [text]);
          }
        };

        const useTextPersistenceOnDisabled = (text, setText, chatDisabled) => {
          const textTmpRef = useRef("");

          useEffect(() => {
            if (chatDisabled) {
              textTmpRef.current = text;
              setText("");
            } else {
              setText(textTmpRef.current);
            }
          }, [chatDisabled]);
        };

        const useAutoFocusOnEditMode = (textInputRef, messageToEdit) => {
          useEffect(() => {
            if (messageToEdit?.isUserMessage()) {
              if (!AUTO_FOCUS)
                setTimeout(() => textInputRef.current?.focus(), 500);
            }
          }, [messageToEdit]);
        };

        useTypingTrigger(text, channel);
        useTextPersistenceOnDisabled(text, onChangeText, inputDisabled);
        useAutoFocusOnEditMode(textInputRef, messageToEdit);

        const onPressToMention = (user, searchStringRange) => {
          const mentionedMessageText = mentionManager.asMentionedMessageText(
            user,
            true
          );
          const range = {
            start: searchStringRange.start,
            end: searchStringRange.start + mentionedMessageText.length - 1,
          };

          onChangeText(
            replace(
              text,
              searchStringRange.start,
              searchStringRange.end,
              mentionedMessageText
            ),
            { user, range }
          );
        };

        const SafeAreaBottom = ({ height }) => {
          return <View style={{ height }} />;
        };

        if (!shouldRenderInput) {
          return <SafeAreaBottom height={bottom} />;
        }

        const props = {
          channel,
          messageToEdit,
          setMessageToEdit,
          inputMuted,
          inputFrozen,
          inputDisabled,
          keyboardAvoidOffset,
          shouldRenderInput,
          onPressSendUserMessage,
          onPressSendFileMessage,
          onPressUpdateUserMessage,
          onPressUpdateFileMessage,
          SuggestedMentionList,
        };

        
        return (
          <>
            <KeyboardAvoidingView
              keyboardVerticalOffset={-bottom + keyboardAvoidOffset}
              behavior={KEYBOARD_AVOID_VIEW_BEHAVIOR}
            >
              <View
                style={{
                  paddingLeft: left,
                  paddingRight: right,
                  backgroundColor: colors.background,
                }}
              >
                <View
                  onLayout={(e) => setInputHeight(e.nativeEvent.layout.height)}
                  style={styles.inputContainer}
                >
                  {inputMode === "send" && (
                    <CustomSendInput
                      {...props}
                      key={inputKeyToRemount}
                      ref={textInputRef}
                      text={text}
                      onChangeText={onChangeText}
                      onSelectionChange={onSelectionChange}
                      mentionedUsers={mentionedUsers}
                      variant="underline"
                    />
                  )}
                </View>
                <SafeAreaBottom height={bottom} />
              </View>
            </KeyboardAvoidingView>
            {mentionAvailable && SuggestedMentionList && (
              <SuggestedMentionList
                text={text}
                selection={selection}
                inputHeight={inputHeight}
                topInset={top}
                bottomInset={bottom}
                onPressToMention={onPressToMention}
                mentionedUsers={mentionedUsers}
              />
            )}
          </>
        );
      };

And, Our CustomSendInput code is as follows:

const CustomSendInput = forwardRef(function CustomSendInput(
          {
            onPressSendUserMessage,
            onPressSendFileMessage,
            text,
            onChangeText,
            onSelectionChange,
            mentionedUsers,
            inputDisabled,
            inputFrozen,
            inputMuted,
          },
          ref
        ) {
          const { mentionManager, imageCompressionConfig, features } =
            useSendbirdChat();
          const { fileService, mediaService } = usePlatformService();
          const { STRINGS } = useLocalization();
          const { openSheet } = useBottomSheet();
          const { alert } = useAlert();
          const toast = useToast();

          const onFailureToSend = () =>
            toast.show(STRINGS.TOAST.SEND_MSG_ERROR, "error");

          const sendUserMessage = () => {
            const mentionType = MentionType.USERS;
            const mentionedUserIds = mentionedUsers.map((it) => it.user.userId);
            const mentionedMessageTemplate =
              mentionManager.textToMentionedMessageTemplate(
                text,
                mentionedUsers
              );

            if (onPressSendUserMessage) {
              onPressSendUserMessage({
                message: text,
                mentionType,
                mentionedUserIds,
                mentionedMessageTemplate,
              }).catch(onFailureToSend);
            }

            onChangeText("");
          };

          const sendFileMessage = (file) => {
            if (onPressSendFileMessage) {
              onPressSendFileMessage({ file }).catch(onFailureToSend);
            }
          };

          const onPressAttachment = () => {
            openSheet({
              sheetItems: [
                {
                  title: STRINGS.LABELS.CHANNEL_INPUT_ATTACHMENT_CAMERA,
                  icon: "camera",
                  iconColor: inputDisabled
                    ? colors.ui.input.default.disabled.highlight
                    : colors.ui.input.default.active.highlight,
                  onPress: async () => {
                    const mediaFile = await fileService.openCamera({
                      mediaType: "all",
                      onOpenFailure: (error) => {
                        if (
                          error.code === SBUError.CODE.ERR_PERMISSIONS_DENIED
                        ) {
                          alert({
                            title: STRINGS.DIALOG.ALERT_PERMISSIONS_TITLE,
                            message: STRINGS.DIALOG.ALERT_PERMISSIONS_MESSAGE(
                              STRINGS.LABELS.PERMISSION_CAMERA,
                              STRINGS.LABELS.PERMISSION_APP_NAME
                            ),
                            buttons: [
                              {
                                text: STRINGS.DIALOG.ALERT_PERMISSIONS_OK,
                                onPress: () => SBUUtils.openSettings(),
                              },
                            ],
                          });
                        } else {
                          toast.show(STRINGS.TOAST.OPEN_CAMERA_ERROR, "error");
                        }
                      },
                    });

                    if (mediaFile) {
                      // Image compression
                      if (
                        isImage(mediaFile.uri, mediaFile.type) &&
                        shouldCompressImage(
                          mediaFile.type,
                          features.imageCompressionEnabled
                        )
                      ) {
                        await SBUUtils.safeRun(async () => {
                          const compressed = await mediaService.compressImage({
                            uri: mediaFile.uri,
                            maxWidth: imageCompressionConfig.width,
                            maxHeight: imageCompressionConfig.height,
                            compressionRate:
                              imageCompressionConfig.compressionRate,
                          });

                          if (compressed) {
                            mediaFile.uri = compressed.uri;
                            mediaFile.size = compressed.size;
                          }
                        });
                      }

                      sendFileMessage(mediaFile);
                    }
                  },
                },
                {
                  title: STRINGS.LABELS.CHANNEL_INPUT_ATTACHMENT_PHOTO_LIBRARY,
                  icon: "photo",
                  iconColor: inputDisabled
                    ? colors.ui.input.default.disabled.highlight
                    : colors.ui.input.default.active.highlight,
                  onPress: async () => {
                    const mediaFiles = await fileService.openMediaLibrary({
                      selectionLimit: 1,
                      mediaType: "all",
                      onOpenFailure: (error) => {
                        if (
                          error.code === SBUError.CODE.ERR_PERMISSIONS_DENIED
                        ) {
                          alert({
                            title: STRINGS.DIALOG.ALERT_PERMISSIONS_TITLE,
                            message: STRINGS.DIALOG.ALERT_PERMISSIONS_MESSAGE(
                              STRINGS.LABELS.PERMISSION_DEVICE_STORAGE,
                              STRINGS.LABELS.PERMISSION_APP_NAME
                            ),
                            buttons: [
                              {
                                text: STRINGS.DIALOG.ALERT_PERMISSIONS_OK,
                                onPress: () => SBUUtils.openSettings(),
                              },
                            ],
                          });
                        } else {
                          toast.show(
                            STRINGS.TOAST.OPEN_PHOTO_LIBRARY_ERROR,
                            "error"
                          );
                        }
                      },
                    });

                    if (mediaFiles && mediaFiles[0]) {
                      const mediaFile = mediaFiles[0];

                      // Image compression
                      if (
                        isImage(mediaFile.uri, mediaFile.type) &&
                        shouldCompressImage(
                          mediaFile.type,
                          features.imageCompressionEnabled
                        )
                      ) {
                        await SBUUtils.safeRun(async () => {
                          const compressed = await mediaService.compressImage({
                            uri: mediaFile.uri,
                            maxWidth: imageCompressionConfig.width,
                            maxHeight: imageCompressionConfig.height,
                            compressionRate:
                              imageCompressionConfig.compressionRate,
                          });

                          if (compressed) {
                            mediaFile.uri = compressed.uri;
                            mediaFile.size = compressed.size;
                          }
                        });
                      }

                      sendFileMessage(mediaFile);
                    }
                  },
                },
                {
                  title: STRINGS.LABELS.CHANNEL_INPUT_ATTACHMENT_FILES,
                  icon: "document",
                  iconColor: inputDisabled
                    ? colors.ui.input.default.disabled.highlight
                    : colors.ui.input.default.active.highlight,
                  onPress: async () => {
                    const documentFile = await fileService.openDocument({
                      onOpenFailure: () =>
                        toast.show(STRINGS.TOAST.OPEN_FILES_ERROR, "error"),
                    });

                    if (documentFile) {
                      // Image compression
                      if (
                        isImage(documentFile.uri, documentFile.type) &&
                        shouldCompressImage(
                          documentFile.type,
                          features.imageCompressionEnabled
                        )
                      ) {
                        await SBUUtils.safeRun(async () => {
                          const compressed = await mediaService.compressImage({
                            uri: documentFile.uri,
                            maxWidth: imageCompressionConfig.width,
                            maxHeight: imageCompressionConfig.height,
                            compressionRate:
                              imageCompressionConfig.compressionRate,
                          });

                          if (compressed) {
                            documentFile.uri = compressed.uri;
                            documentFile.size = compressed.size;
                          }
                        });
                      }

                      sendFileMessage(documentFile);
                    }
                  },
                },
              ],
            });
          };

          const getPlaceholder = () => {
            if (!inputDisabled)
              return STRINGS.LABELS.CHANNEL_INPUT_PLACEHOLDER_ACTIVE;
            if (inputFrozen)
              return STRINGS.LABELS.CHANNEL_INPUT_PLACEHOLDER_DISABLED;
            if (inputMuted)
              return STRINGS.LABELS.CHANNEL_INPUT_PLACEHOLDER_MUTED;

            return STRINGS.LABELS.CHANNEL_INPUT_PLACEHOLDER_DISABLED;
          };

          return (
            <View style={styles.sendInputContainer}>
              <TouchableOpacity
                onPress={onPressAttachment}
                disabled={inputDisabled}
              >
                <Image
                  source={require("../../../assets/AddAttachment.png")}
                  style={[
                    styles.iconAttach,
                    {
                      resizeMode: "contain",
                      height: 24,
                      width: 24,
                      tintColor: inputDisabled
                        ? colors.ui.input.default.disabled.highlight
                        : colors.ui.input.default.active.highlight,
                    },
                  ]}
                />
              </TouchableOpacity>
              <CustomTextInput
                ref={ref}
                multiline
                disableFullscreenUI
                onSelectionChange={onSelectionChange}
                editable={!inputDisabled}
                onChangeText={onChangeText}
                style={[
                  styles.input,
                  {
                    borderWidth: text.length === 0 ? 0 : 1,

                    borderColor:
                      text.length === 0
                        ? colors?.onBackground01
                        : "rgba(110, 112, 155, 0.75)",
                  },
                ]}
                placeholder={getPlaceholder()}
                text={text}
              >
                {mentionManager.textToMentionedComponents(text, mentionedUsers)}
              </CustomTextInput>
              {Boolean(text.trim()) && (
                <TouchableOpacity
                  onPress={sendUserMessage}
                  disabled={inputDisabled}
                >
                  <Icon
                    color={
                      inputDisabled
                        ? colors.ui.input.default.disabled.highlight
                        : colors.ui.input.default.active.highlight
                    }
                    icon={"send"}
                    size={24}
                    containerStyle={styles.iconSend}
                  />
                </TouchableOpacity>
              )}
            </View>
          );
        });

Here’s our CustomTextInput component:

          const CustomTextInput = forwardRef(function CustomTextInput(
            {
              children,
              style,
              variant = "default",
              editable = true,
              text,
              ...props
            },
            ref
          ) {
            const { typography, colors, palette } = useUIKitTheme();

            const variantStyle = colors["ui"]["input"][variant];
            const inputStyle = editable
              ? variantStyle.active
              : variantStyle.disabled;
            const underlineStyle = variant === "underline" && {
              borderBottomWidth: 2,
              borderBottomColor: inputStyle.highlight,
            };

            return (
              <TextInput
                ref={ref}
                editable={editable}
                selectionColor={palette?.primary500}
                placeholderTextColor={inputStyle.placeholder}
                style={[
                  typography.body3,
                  { paddingVertical: 8, paddingHorizontal: 16 },
                  {
                    color: inputStyle.text,
                    backgroundColor:
                      text.length === 0 ? "#E1E1F5" : inputStyle.background,
                  },
                  underlineStyle,
                  style,
                ]}
                {...props}
              >
                {children}
              </TextInput>
            );
          });

What’s the reason behind this weird behaviour? We are following the same steps for the functionality as used in default module input component.

Here’s a video depicting it more clearly, what our issue issue.
https://drive.google.com/file/d/1-4VXFY-cjJvX9_gaK0LLGgc02rHu7bfW/view?usp=sharing

Update: was able to resolve this issue.