Skip to content

Commit 305af4b

Browse files
authored
Merge pull request #42823 from dragnoir/41803-fix
Fix: intercept mouse selection when out of input field
2 parents d3434cb + f66765b commit 305af4b

File tree

5 files changed

+77
-12
lines changed

5 files changed

+77
-12
lines changed

src/components/MoneyRequestAmountInput.tsx

+13-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type {ForwardedRef} from 'react';
22
import React, {useCallback, useEffect, useImperativeHandle, useRef, useState} from 'react';
33
import type {NativeSyntheticEvent, StyleProp, TextInputSelectionChangeEventData, TextStyle, ViewStyle} from 'react-native';
44
import useLocalize from '@hooks/useLocalize';
5+
import {useMouseContext} from '@hooks/useMouseContext';
56
import * as Browser from '@libs/Browser';
67
import * as CurrencyUtils from '@libs/CurrencyUtils';
78
import getOperatingSystem from '@libs/getOperatingSystem';
@@ -258,6 +259,16 @@ function MoneyRequestAmountInput(
258259

259260
const formattedAmount = MoneyRequestUtils.replaceAllDigits(currentAmount, toLocaleDigit);
260261

262+
const {setMouseDown, setMouseUp} = useMouseContext();
263+
const handleMouseDown = (e: React.MouseEvent<Element, MouseEvent>) => {
264+
e.stopPropagation();
265+
setMouseDown();
266+
};
267+
const handleMouseUp = (e: React.MouseEvent<Element, MouseEvent>) => {
268+
e.stopPropagation();
269+
setMouseUp();
270+
};
271+
261272
return (
262273
<TextInputWithCurrencySymbol
263274
autoGrow={autoGrow}
@@ -298,7 +309,8 @@ function MoneyRequestAmountInput(
298309
touchableInputWrapperStyle={props.touchableInputWrapperStyle}
299310
maxLength={maxLength}
300311
hideFocusedState={hideFocusedState}
301-
onMouseDown={(event) => event.stopPropagation()}
312+
onMouseDown={handleMouseDown}
313+
onMouseUp={handleMouseUp}
302314
/>
303315
);
304316
}

src/components/MoneyRequestConfirmationList.tsx

+14-11
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import type {OnyxCollection, OnyxEntry} from 'react-native-onyx';
99
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
1010
import useDebouncedState from '@hooks/useDebouncedState';
1111
import useLocalize from '@hooks/useLocalize';
12+
import {MouseProvider} from '@hooks/useMouseContext';
1213
import useNetwork from '@hooks/useNetwork';
1314
import usePermissions from '@hooks/usePermissions';
1415
import usePrevious from '@hooks/usePrevious';
@@ -1228,17 +1229,19 @@ function MoneyRequestConfirmationList({
12281229
);
12291230

12301231
return (
1231-
<SelectionList<MoneyRequestConfirmationListItem>
1232-
sections={sections}
1233-
ListItem={UserListItem}
1234-
onSelectRow={navigateToReportOrUserDetail}
1235-
shouldDebounceRowSelect
1236-
canSelectMultiple={false}
1237-
shouldPreventDefaultFocusOnSelectRow
1238-
footerContent={footerContent}
1239-
listFooterContent={listFooterContent}
1240-
containerStyle={[styles.flexBasisAuto]}
1241-
/>
1232+
<MouseProvider>
1233+
<SelectionList<MoneyRequestConfirmationListItem>
1234+
sections={sections}
1235+
ListItem={UserListItem}
1236+
onSelectRow={navigateToReportOrUserDetail}
1237+
shouldDebounceRowSelect
1238+
canSelectMultiple={false}
1239+
shouldPreventDefaultFocusOnSelectRow
1240+
footerContent={footerContent}
1241+
listFooterContent={listFooterContent}
1242+
containerStyle={[styles.flexBasisAuto]}
1243+
/>
1244+
</MouseProvider>
12421245
);
12431246
}
12441247

src/components/SelectionList/BaseListItem.tsx

+12
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import * as Expensicons from '@components/Icon/Expensicons';
55
import OfflineWithFeedback from '@components/OfflineWithFeedback';
66
import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
77
import useHover from '@hooks/useHover';
8+
import {useMouseContext} from '@hooks/useMouseContext';
89
import useSyncFocus from '@hooks/useSyncFocus';
910
import useTheme from '@hooks/useTheme';
1011
import useThemeStyles from '@hooks/useThemeStyles';
@@ -36,11 +37,16 @@ function BaseListItem<TItem extends ListItem>({
3637
const theme = useTheme();
3738
const styles = useThemeStyles();
3839
const {hovered, bind} = useHover();
40+
const {isMouseDownOnInput, setMouseUp} = useMouseContext();
3941

4042
const pressableRef = useRef<View>(null);
4143

4244
// Sync focus on an item
4345
useSyncFocus(pressableRef, Boolean(isFocused), shouldSyncFocus);
46+
const handleMouseUp = (e: React.MouseEvent<Element, MouseEvent>) => {
47+
e.stopPropagation();
48+
setMouseUp();
49+
};
4450

4551
const rightHandSideComponentRender = () => {
4652
if (canSelectMultiple || !rightHandSideComponent) {
@@ -67,6 +73,10 @@ function BaseListItem<TItem extends ListItem>({
6773
{...bind}
6874
ref={pressableRef}
6975
onPress={(e) => {
76+
if (isMouseDownOnInput) {
77+
e?.stopPropagation(); // Preventing the click action
78+
return;
79+
}
7080
if (shouldPreventEnterKeySubmit && e && 'key' in e && e.key === CONST.KEYBOARD_SHORTCUTS.ENTER.shortcutKey) {
7181
return;
7282
}
@@ -82,6 +92,8 @@ function BaseListItem<TItem extends ListItem>({
8292
id={keyForList ?? ''}
8393
style={pressableStyle}
8494
onFocus={onFocus}
95+
onMouseUp={handleMouseUp}
96+
onMouseLeave={handleMouseUp}
8597
tabIndex={item.tabIndex}
8698
>
8799
<View style={wrapperStyle}>

src/components/TextInputWithCurrencySymbol/types.ts

+5
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ type TextInputWithCurrencySymbolProps = {
3737
*/
3838
onMouseDown?: ((e: React.MouseEvent) => void) | undefined;
3939

40+
/**
41+
* Callback that is called when the text input is pressed up
42+
*/
43+
onMouseUp?: ((e: React.MouseEvent) => void) | undefined;
44+
4045
/** Whether the currency symbol is pressable */
4146
isCurrencyPressable: boolean;
4247

src/hooks/useMouseContext.tsx

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import type {ReactNode} from 'react';
2+
import React, {createContext, useContext, useMemo, useState} from 'react';
3+
4+
type MouseContextProps = {
5+
isMouseDownOnInput: boolean;
6+
setMouseDown: () => void;
7+
setMouseUp: () => void;
8+
};
9+
10+
const MouseContext = createContext<MouseContextProps>({
11+
isMouseDownOnInput: false,
12+
setMouseDown: () => {},
13+
setMouseUp: () => {},
14+
});
15+
16+
type MouseProviderProps = {
17+
children: ReactNode;
18+
};
19+
20+
function MouseProvider({children}: MouseProviderProps) {
21+
const [isMouseDownOnInput, setIsMouseDownOnInput] = useState(false);
22+
23+
const setMouseDown = () => setIsMouseDownOnInput(true);
24+
const setMouseUp = () => setIsMouseDownOnInput(false);
25+
26+
const value = useMemo(() => ({isMouseDownOnInput, setMouseDown, setMouseUp}), [isMouseDownOnInput]);
27+
28+
return <MouseContext.Provider value={value}>{children}</MouseContext.Provider>;
29+
}
30+
31+
const useMouseContext = () => useContext(MouseContext);
32+
33+
export {MouseProvider, useMouseContext};

0 commit comments

Comments
 (0)