diff --git a/patches/@expensify/react-native-live-markdown/@expensify+react-native-live-markdown+0.1.317.patch b/patches/@expensify/react-native-live-markdown/@expensify+react-native-live-markdown+0.1.317.patch new file mode 100644 index 0000000000000..ab04f92db7f20 --- /dev/null +++ b/patches/@expensify/react-native-live-markdown/@expensify+react-native-live-markdown+0.1.317.patch @@ -0,0 +1,118 @@ +diff --git a/node_modules/@expensify/react-native-live-markdown/lib/module/MarkdownTextInput.web.js b/node_modules/@expensify/react-native-live-markdown/lib/module/MarkdownTextInput.web.js +index e36195f..3a3ae72 100644 +--- a/node_modules/@expensify/react-native-live-markdown/lib/module/MarkdownTextInput.web.js ++++ b/node_modules/@expensify/react-native-live-markdown/lib/module/MarkdownTextInput.web.js +@@ -21,6 +21,7 @@ const MarkdownTextInput = /*#__PURE__*/React.forwardRef(({ + autoCapitalize = 'sentences', + autoCorrect = true, + blurOnSubmit = false, ++ submitBehavior, + caretHidden, + clearTextOnFocus, + dir = 'auto', +@@ -359,8 +360,19 @@ const MarkdownTextInput = /*#__PURE__*/React.forwardRef(({ + handleOnChangeText(e); + return; + } +- const blurOnSubmitDefault = !multiline; +- const shouldBlurOnSubmit = blurOnSubmit === null ? blurOnSubmitDefault : blurOnSubmit; ++ // Support submitBehavior prop (React Native 0.73+), fallback to blurOnSubmit for backwards compatibility ++ let shouldBlurOnSubmit; ++ let 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 ++ const blurOnSubmitDefault = !multiline; ++ shouldBlurOnSubmit = blurOnSubmit === null ? blurOnSubmitDefault : blurOnSubmit; ++ shouldSubmit = blurOnSubmit || !multiline; ++ } + const nativeEvent = e.nativeEvent; + const isComposing = isEventComposing(nativeEvent); + const event = e; +@@ -373,18 +385,19 @@ const MarkdownTextInput = /*#__PURE__*/React.forwardRef(({ + !isComposing && !e.isDefaultPrevented()) { + // prevent "Enter" from inserting a newline or submitting a form + e.preventDefault(); +- if (!e.shiftKey && (blurOnSubmit || !multiline) && onSubmitEditing) { ++ // submitBehavior === 'newline' means don't submit, just insert newline (default behavior) ++ if (!e.shiftKey && shouldSubmit && onSubmitEditing) { + onSubmitEditing(event); +- } 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 = 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) {