tags.
+ // Thanks to that in every situation we have proper amount of new lines in our parsed text. Without it pressing enter in empty lines will add 2 more new lines.
+ insertText(e, '\n');
+ }
+- if (!e.shiftKey && (shouldBlurOnSubmit && hostNode !== null || !multiline)) {
++ if (!e.shiftKey && shouldBlurOnSubmit && hostNode !== null) {
+ setTimeout(() => divRef.current && divRef.current.blur(), 0);
+ }
+ }
+- }, [multiline, blurOnSubmit, setEventProps, onKeyPress, handleOnChangeText, onSubmitEditing, insertText]);
++ }, [multiline, blurOnSubmit, submitBehavior, setEventProps, onKeyPress, handleOnChangeText, onSubmitEditing, insertText]);
+ const handleFocus = useCallback(event => {
+ hasJustBeenFocused.current = true;
+ const e = event;
+diff --git a/node_modules/@expensify/react-native-live-markdown/src/MarkdownTextInput.web.tsx b/node_modules/@expensify/react-native-live-markdown/src/MarkdownTextInput.web.tsx
+index fa3283d..59f02c6 100644
+--- a/node_modules/@expensify/react-native-live-markdown/src/MarkdownTextInput.web.tsx
++++ b/node_modules/@expensify/react-native-live-markdown/src/MarkdownTextInput.web.tsx
+@@ -87,6 +87,7 @@ const MarkdownTextInput = React.forwardRef
);
+- } else if (multiline) {
++ } else if (multiline && (!shouldSubmit || e.shiftKey)) {
+ // We need to change normal behavior of "Enter" key to insert a line breaks, to prevent wrapping contentEditable text in tags.
+ // Thanks to that in every situation we have proper amount of new lines in our parsed text. Without it pressing enter in empty lines will add 2 more new lines.
+ insertText(e, '\n');
+ }
+- if (!e.shiftKey && ((shouldBlurOnSubmit && hostNode !== null) || !multiline)) {
++ if (!e.shiftKey && shouldBlurOnSubmit && hostNode !== null) {
+ setTimeout(() => divRef.current && divRef.current.blur(), 0);
+ }
+ }
+ },
+- [multiline, blurOnSubmit, setEventProps, onKeyPress, handleOnChangeText, onSubmitEditing, insertText],
++ [multiline, blurOnSubmit, submitBehavior, setEventProps, onKeyPress, handleOnChangeText, onSubmitEditing, insertText],
+ );
+
+ const handleFocus: FocusEventHandler = useCallback(
diff --git a/patches/@expensify/react-native-live-markdown/details.md b/patches/@expensify/react-native-live-markdown/details.md
new file mode 100644
index 0000000000000..6a7cbf31d75a9
--- /dev/null
+++ b/patches/@expensify/react-native-live-markdown/details.md
@@ -0,0 +1,18 @@
+# # `react-native-live-markdown` patches
+
+### [@expensify+react-native-live-markdown+0.1.317.patch](@expensify+react-native-live-markdown+0.1.317.patch)
+
+- Reason:
+ ```
+ Adds support for the `submitBehavior` prop in MarkdownTextInput component for web.
+ React Native deprecated `blurOnSubmit` in favor of `submitBehavior` (React Native 0.73+),
+ but @expensify/react-native-live-markdown's MarkdownTextInput on web doesn't natively
+ support this prop. This patch implements the web equivalent behavior, mapping
+ `submitBehavior` values ('submit', 'blurAndSubmit', 'newline') to the appropriate
+ keyboard handling logic in handleKeyPress while maintaining backwards compatibility with
+ the deprecated `blurOnSubmit` prop. This aligns MarkdownTextInput with React Native's
+ TextInput API and react-native-web's TextInput implementation.
+ ```
+- Upstream PR/issue: https://github.com/Expensify/react-native-live-markdown/issues/744
+- E/App issue: https://github.com/Expensify/App/issues/73782
+- PR introducing patch: https://github.com/Expensify/App/pull/76332
\ No newline at end of file
diff --git a/patches/react-native-web/details.md b/patches/react-native-web/details.md
index 8c7df48f3ea27..ee7282178fc28 100644
--- a/patches/react-native-web/details.md
+++ b/patches/react-native-web/details.md
@@ -130,4 +130,19 @@
- Upstream PR/issue: This was a patch on top of patches 008 and 009 of react-native-web.
- E/App issue: https://github.com/Expensify/App/issues/66821
-- PR introducing patch: https://github.com/Expensify/App/pull/69820
\ No newline at end of file
+- PR introducing patch: https://github.com/Expensify/App/pull/69820
+
+### [react-native-web+0.21.2+012+submitBehavior-support.patch](react-native-web+0.21.2+012+submitBehavior-support.patch)
+
+- Reason:
+ ```
+ Adds support for the `submitBehavior` prop in TextInput component for web.
+ React Native deprecated `blurOnSubmit` in favor of `submitBehavior` (React Native 0.73+),
+ but React Native Web doesn't natively support this prop. This patch implements the web
+ equivalent behavior, mapping `submitBehavior` values ('submit', 'blurAndSubmit', 'newline')
+ to the appropriate keyboard handling logic while maintaining backwards compatibility with
+ the deprecated `blurOnSubmit` prop.
+ ```
+- Upstream PR/issue: https://github.com/necolas/react-native-web/issues/2817
+- E/App issue: https://github.com/Expensify/App/issues/73782
+- PR introducing patch: https://github.com/Expensify/App/pull/76332
\ No newline at end of file
diff --git a/patches/react-native-web/react-native-web+0.21.2+012+submitBehavior-support.patch b/patches/react-native-web/react-native-web+0.21.2+012+submitBehavior-support.patch
new file mode 100644
index 0000000000000..c62903bebe1ce
--- /dev/null
+++ b/patches/react-native-web/react-native-web+0.21.2+012+submitBehavior-support.patch
@@ -0,0 +1,44 @@
+diff --git a/node_modules/react-native-web/dist/exports/TextInput/index.js b/node_modules/react-native-web/dist/exports/TextInput/index.js
+index 0f476a7..51555b5 100644
+--- a/node_modules/react-native-web/dist/exports/TextInput/index.js
++++ b/node_modules/react-native-web/dist/exports/TextInput/index.js
+@@ -84,6 +89,7 @@ var TextInput = /*#__PURE__*/React.forwardRef((props, forwardedRef) => {
+ _props$autoCorrect = props.autoCorrect,
+ autoCorrect = _props$autoCorrect === void 0 ? true : _props$autoCorrect,
+ blurOnSubmit = props.blurOnSubmit,
++ submitBehavior = props.submitBehavior,
+ caretHidden = props.caretHidden,
+ clearTextOnFocus = props.clearTextOnFocus,
+ dir = props.dir,
+@@ -271,8 +277,19 @@ var TextInput = /*#__PURE__*/React.forwardRef((props, forwardedRef) => {
+ var hostNode = e.target;
+ // Prevent key events bubbling (see #612)
+ e.stopPropagation();
+- var blurOnSubmitDefault = !multiline;
+- var shouldBlurOnSubmit = blurOnSubmit == null ? blurOnSubmitDefault : blurOnSubmit;
++ // Support submitBehavior prop (React Native 0.73+), fallback to blurOnSubmit for backwards compatibility
++ var shouldBlurOnSubmit;
++ var shouldSubmit;
++ if (submitBehavior != null) {
++ // submitBehavior takes precedence over blurOnSubmit
++ shouldSubmit = submitBehavior === 'submit' || submitBehavior === 'blurAndSubmit';
++ shouldBlurOnSubmit = submitBehavior === 'blurAndSubmit';
++ } else {
++ // Fallback to blurOnSubmit logic for backwards compatibility
++ var blurOnSubmitDefault = !multiline;
++ shouldBlurOnSubmit = blurOnSubmit == null ? blurOnSubmitDefault : blurOnSubmit;
++ shouldSubmit = blurOnSubmit || !multiline;
++ }
+ var nativeEvent = e.nativeEvent;
+ var isComposing = isEventComposing(nativeEvent);
+ if (onKeyPress) {
+@@ -281,7 +298,8 @@ var TextInput = /*#__PURE__*/React.forwardRef((props, forwardedRef) => {
+ if (e.key === 'Enter' && !e.shiftKey &&
+ // Do not call submit if composition is occuring.
+ !isComposing && !e.isDefaultPrevented()) {
+- if ((blurOnSubmit || !multiline) && onSubmitEditing) {
++ // submitBehavior === 'newline' means don't submit, just insert newline (default behavior)
++ if (shouldSubmit && onSubmitEditing) {
+ // prevent "Enter" from inserting a newline or submitting a form
+ e.preventDefault();
+ nativeEvent.text = e.target.value;
\ No newline at end of file
diff --git a/src/components/Form/InputWrapper.tsx b/src/components/Form/InputWrapper.tsx
index 30059c844a44e..ecc6debdc0408 100644
--- a/src/components/Form/InputWrapper.tsx
+++ b/src/components/Form/InputWrapper.tsx
@@ -1,5 +1,6 @@
import type {ComponentPropsWithoutRef, ComponentType, ForwardedRef} from 'react';
import React, {useContext} from 'react';
+import type {SubmitBehavior} from 'react-native';
import type {AnimatedTextInputRef} from '@components/RNTextInput';
import RoomNameInput from '@components/RoomNameInput';
import type RoomNameInputProps from '@components/RoomNameInput/types';
@@ -17,7 +18,7 @@ const textInputBasedComponents: TextInputBasedComponents = new Set([TextInput, R
type ComputedComponentSpecificRegistrationParams = {
shouldSubmitForm: boolean;
shouldSetTouchedOnBlurOnly: boolean;
- blurOnSubmit: boolean | undefined;
+ submitBehavior?: SubmitBehavior;
};
function computeComponentSpecificRegistrationParams({
@@ -25,7 +26,7 @@ function computeComponentSpecificRegistrationParams({
shouldSubmitForm,
multiline,
autoGrowHeight,
- blurOnSubmit,
+ submitBehavior,
}: InputComponentBaseProps): ComputedComponentSpecificRegistrationParams {
if (textInputBasedComponents.has(InputComponent)) {
const isEffectivelyMultiline = !!multiline || !!autoGrowHeight;
@@ -46,7 +47,7 @@ function computeComponentSpecificRegistrationParams({
// calling some methods too early or twice, so we had to add this check to prevent that side effect.
// For now this side effect happened only in `TextInput` components.
shouldSetTouchedOnBlurOnly: true,
- blurOnSubmit: (isEffectivelyMultiline && shouldReallySubmitForm) || blurOnSubmit,
+ submitBehavior: isEffectivelyMultiline && shouldReallySubmitForm ? 'blurAndSubmit' : submitBehavior,
shouldSubmitForm: shouldReallySubmitForm,
};
}
@@ -54,7 +55,7 @@ function computeComponentSpecificRegistrationParams({
return {
shouldSetTouchedOnBlurOnly: false,
// Forward the originally provided value
- blurOnSubmit,
+ submitBehavior,
shouldSubmitForm: !!shouldSubmitForm,
};
}
@@ -80,9 +81,9 @@ function InputWrapper({
const {InputComponent, inputID, valueType = 'string', shouldSubmitForm: propShouldSubmitForm, ...rest} = props as InputComponentBaseProps;
const {registerInput} = useContext(FormContext);
- const {shouldSetTouchedOnBlurOnly, blurOnSubmit, shouldSubmitForm} = computeComponentSpecificRegistrationParams(props as InputComponentBaseProps);
+ const {shouldSetTouchedOnBlurOnly, submitBehavior, shouldSubmitForm} = computeComponentSpecificRegistrationParams(props as InputComponentBaseProps);
// eslint-disable-next-line react-compiler/react-compiler
- const {key, ...registerInputProps} = registerInput(inputID, shouldSubmitForm, {ref, valueType, ...rest, shouldSetTouchedOnBlurOnly, blurOnSubmit});
+ const {key, ...registerInputProps} = registerInput(inputID, shouldSubmitForm, {ref, valueType, ...rest, shouldSetTouchedOnBlurOnly, submitBehavior});
return (
= Input
ref?: Ref;
multiline?: boolean;
autoGrowHeight?: boolean;
- blurOnSubmit?: boolean;
+ submitBehavior?: SubmitBehavior;
shouldSubmitForm?: boolean;
uncontrolled?: boolean;
};
diff --git a/src/pages/signin/LoginForm/BaseLoginForm.tsx b/src/pages/signin/LoginForm/BaseLoginForm.tsx
index e08fd6c8f5af0..fd9a03db3bfee 100644
--- a/src/pages/signin/LoginForm/BaseLoginForm.tsx
+++ b/src/pages/signin/LoginForm/BaseLoginForm.tsx
@@ -40,7 +40,7 @@ import type LoginFormProps from './types';
type BaseLoginFormProps = WithToggleVisibilityViewProps & LoginFormProps;
-function BaseLoginForm({blurOnSubmit = false, isVisible, ref}: BaseLoginFormProps) {
+function BaseLoginForm({submitBehavior = 'submit', isVisible, ref}: BaseLoginFormProps) {
const {login, setLogin} = useLogin();
const [account] = useOnyx(ONYXKEYS.ACCOUNT, {canBeMissing: true});
const [closeAccount] = useOnyx(ONYXKEYS.FORMS.CLOSE_ACCOUNT_FORM, {canBeMissing: true});
@@ -175,7 +175,7 @@ function BaseLoginForm({blurOnSubmit = false, isVisible, ref}: BaseLoginFormProp
}, [account?.isLoading]);
useEffect(() => {
- if (blurOnSubmit) {
+ if (submitBehavior === 'blurAndSubmit') {
input.current?.blur();
}
@@ -184,7 +184,7 @@ function BaseLoginForm({blurOnSubmit = false, isVisible, ref}: BaseLoginFormProp
return;
}
input.current?.focus();
- }, [blurOnSubmit, isVisible, prevIsVisible]);
+ }, [submitBehavior, isVisible, prevIsVisible]);
useImperativeHandle(ref, () => ({
isInputFocused() {
diff --git a/src/pages/signin/LoginForm/types.ts b/src/pages/signin/LoginForm/types.ts
index 679c32834250b..e9fbe6f74c861 100644
--- a/src/pages/signin/LoginForm/types.ts
+++ b/src/pages/signin/LoginForm/types.ts
@@ -1,11 +1,12 @@
import type {ForwardedRef} from 'react';
+import type {SubmitBehavior} from 'react-native';
type LoginFormProps = {
/** Function used to scroll to the top of the page */
scrollPageToTop?: () => void;
/** Should we dismiss the keyboard when transitioning away from the page? */
- blurOnSubmit?: boolean;
+ submitBehavior?: SubmitBehavior;
/** Whether the content is visible. */
isVisible: boolean;
diff --git a/src/pages/signin/SignInPage.tsx b/src/pages/signin/SignInPage.tsx
index ddb4418ffe2fc..1a4987ca5ac42 100644
--- a/src/pages/signin/SignInPage.tsx
+++ b/src/pages/signin/SignInPage.tsx
@@ -314,7 +314,7 @@ function SignInPage({ref}: SignInPageProps) {