Skip to content

Commit 62fa3b5

Browse files
authored
Merge pull request Expensify#68289 from software-mansion-labs/jakubkalinski0/Fix-console-errors-related-to-forwardRef-batch1
Jakubkalinski0/fix console errors related to forward ref batch1
2 parents c71f5f9 + 299197c commit 62fa3b5

37 files changed

Lines changed: 346 additions & 317 deletions

src/components/BaseMiniContextMenuItem.tsx

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import type {ForwardedRef} from 'react';
21
import React from 'react';
32
import type {PressableStateCallbackType} from 'react-native';
43
import {View} from 'react-native';
@@ -9,6 +8,7 @@ import getButtonState from '@libs/getButtonState';
98
import ReportActionComposeFocusManager from '@libs/ReportActionComposeFocusManager';
109
import variables from '@styles/variables';
1110
import CONST from '@src/CONST';
11+
import type {PressableRef} from './Pressable/GenericPressable/types';
1212
import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback';
1313
import Tooltip from './Tooltip/PopoverAnchorTooltip';
1414

@@ -36,16 +36,18 @@ type BaseMiniContextMenuItemProps = {
3636
* Can be used to control the click event, and for example whether or not to lose focus from the composer when pressing the item
3737
*/
3838
shouldPreventDefaultFocusOnPress?: boolean;
39+
40+
/**
41+
* Reference to the outer element
42+
*/
43+
ref?: PressableRef;
3944
};
4045

4146
/**
4247
* Component that renders a mini context menu item with a
4348
* pressable. Also renders a tooltip when hovering the item.
4449
*/
45-
function BaseMiniContextMenuItem(
46-
{tooltipText, onPress, children, isDelayButtonStateComplete = true, shouldPreventDefaultFocusOnPress = true}: BaseMiniContextMenuItemProps,
47-
ref: ForwardedRef<View>,
48-
) {
50+
function BaseMiniContextMenuItem({tooltipText, onPress, children, isDelayButtonStateComplete = true, shouldPreventDefaultFocusOnPress = true, ref}: BaseMiniContextMenuItemProps) {
4951
const styles = useThemeStyles();
5052
const StyleUtils = useStyleUtils();
5153
return (
@@ -95,4 +97,4 @@ function BaseMiniContextMenuItem(
9597

9698
BaseMiniContextMenuItem.displayName = 'BaseMiniContextMenuItem';
9799

98-
export default React.forwardRef(BaseMiniContextMenuItem);
100+
export default BaseMiniContextMenuItem;

src/components/Button/index.tsx

Lines changed: 67 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type {GestureResponderEvent, LayoutChangeEvent, StyleProp, TextStyle, Vie
55
import {ActivityIndicator, StyleSheet, View} from 'react-native';
66
import Icon from '@components/Icon';
77
import * as Expensicons from '@components/Icon/Expensicons';
8+
import type {PressableRef} from '@components/Pressable/GenericPressable/types';
89
import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
910
import Text from '@components/Text';
1011
import withNavigationFallback from '@components/withNavigationFallback';
@@ -161,6 +162,11 @@ type ButtonProps = Partial<ChildrenProps> & {
161162
* This is needed for buttons that allow content to display under them.
162163
*/
163164
shouldBlendOpacity?: boolean;
165+
166+
/**
167+
* Reference to the outer element.
168+
*/
169+
ref?: ForwardedRef<View>;
164170
};
165171

166172
type KeyboardShortcutComponentProps = Pick<ButtonProps, 'isDisabled' | 'isLoading' | 'onPress' | 'pressOnEnter' | 'allowBubble' | 'enterKeyEventListenerPriority' | 'isPressOnEnterActive'>;
@@ -209,67 +215,65 @@ function KeyboardShortcutComponent({
209215

210216
KeyboardShortcutComponent.displayName = 'KeyboardShortcutComponent';
211217

212-
function Button(
213-
{
214-
allowBubble = false,
215-
216-
iconRight = Expensicons.ArrowRight,
217-
iconFill,
218-
iconHoverFill,
219-
icon = null,
220-
iconStyles = [],
221-
iconRightStyles = [],
222-
iconWrapperStyles = [],
223-
text = '',
224-
225-
small = false,
226-
large = false,
227-
medium = !small && !large,
228-
229-
isLoading = false,
230-
isDisabled = false,
231-
232-
onLayout = () => {},
233-
onPress = () => {},
234-
onLongPress = () => {},
235-
onPressIn = () => {},
236-
onPressOut = () => {},
237-
onMouseDown = undefined,
238-
239-
pressOnEnter = false,
240-
enterKeyEventListenerPriority = 0,
241-
242-
style = [],
243-
disabledStyle,
244-
innerStyles = [],
245-
textStyles = [],
246-
textHoverStyles = [],
247-
248-
shouldUseDefaultHover = true,
249-
hoverStyles = undefined,
250-
success = false,
251-
danger = false,
252-
253-
shouldRemoveRightBorderRadius = false,
254-
shouldRemoveLeftBorderRadius = false,
255-
shouldEnableHapticFeedback = false,
256-
isLongPressDisabled = false,
257-
shouldShowRightIcon = false,
258-
259-
id = '',
260-
testID = undefined,
261-
accessibilityLabel = '',
262-
isSplitButton = false,
263-
link = false,
264-
isContentCentered = false,
265-
isPressOnEnterActive,
266-
isNested = false,
267-
secondLineText = '',
268-
shouldBlendOpacity = false,
269-
...rest
270-
}: ButtonProps,
271-
ref: ForwardedRef<View>,
272-
) {
218+
function Button({
219+
allowBubble = false,
220+
221+
iconRight = Expensicons.ArrowRight,
222+
iconFill,
223+
iconHoverFill,
224+
icon = null,
225+
iconStyles = [],
226+
iconRightStyles = [],
227+
iconWrapperStyles = [],
228+
text = '',
229+
230+
small = false,
231+
large = false,
232+
medium = !small && !large,
233+
234+
isLoading = false,
235+
isDisabled = false,
236+
237+
onLayout = () => {},
238+
onPress = () => {},
239+
onLongPress = () => {},
240+
onPressIn = () => {},
241+
onPressOut = () => {},
242+
onMouseDown = undefined,
243+
244+
pressOnEnter = false,
245+
enterKeyEventListenerPriority = 0,
246+
247+
style = [],
248+
disabledStyle,
249+
innerStyles = [],
250+
textStyles = [],
251+
textHoverStyles = [],
252+
253+
shouldUseDefaultHover = true,
254+
hoverStyles = undefined,
255+
success = false,
256+
danger = false,
257+
258+
shouldRemoveRightBorderRadius = false,
259+
shouldRemoveLeftBorderRadius = false,
260+
shouldEnableHapticFeedback = false,
261+
isLongPressDisabled = false,
262+
shouldShowRightIcon = false,
263+
264+
id = '',
265+
testID = undefined,
266+
accessibilityLabel = '',
267+
isSplitButton = false,
268+
link = false,
269+
isContentCentered = false,
270+
isPressOnEnterActive,
271+
isNested = false,
272+
secondLineText = '',
273+
shouldBlendOpacity = false,
274+
ref,
275+
...rest
276+
}: ButtonProps) {
273277
const theme = useTheme();
274278
const styles = useThemeStyles();
275279
const StyleUtils = useStyleUtils();
@@ -447,7 +451,7 @@ function Button(
447451
dataSet={{
448452
listener: pressOnEnter ? CONST.KEYBOARD_SHORTCUTS.ENTER.shortcutKey : undefined,
449453
}}
450-
ref={ref}
454+
ref={ref as PressableRef}
451455
onLayout={onLayout}
452456
onPress={(event) => {
453457
if (event?.type === 'click') {
@@ -517,6 +521,6 @@ function Button(
517521

518522
Button.displayName = 'Button';
519523

520-
export default withNavigationFallback(React.forwardRef(Button));
524+
export default withNavigationFallback(Button);
521525

522526
export type {ButtonProps};

src/components/Checkbox.tsx

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type {ForwardedRef, MouseEventHandler, KeyboardEvent as ReactKeyboardEvent} from 'react';
2-
import React, {forwardRef} from 'react';
2+
import React from 'react';
33
import type {GestureResponderEvent, StyleProp, ViewStyle} from 'react-native';
44
import {View} from 'react-native';
55
import useStyleUtils from '@hooks/useStyleUtils';
@@ -9,6 +9,7 @@ import CONST from '@src/CONST';
99
import type ChildrenProps from '@src/types/utils/ChildrenProps';
1010
import Icon from './Icon';
1111
import * as Expensicons from './Icon/Expensicons';
12+
import type {PressableRef} from './Pressable/GenericPressable/types';
1213
import PressableWithFeedback from './Pressable/PressableWithFeedback';
1314

1415
type CheckboxProps = Partial<ChildrenProps> & {
@@ -56,29 +57,30 @@ type CheckboxProps = Partial<ChildrenProps> & {
5657

5758
/** Additional styles to add to checkbox wrapper */
5859
wrapperStyle?: StyleProp<ViewStyle>;
60+
61+
/** Reference to the outer element */
62+
ref?: ForwardedRef<View>;
5963
};
6064

61-
function Checkbox(
62-
{
63-
isChecked = false,
64-
isIndeterminate = false,
65-
hasError = false,
66-
disabled = false,
67-
style,
68-
containerStyle,
69-
children = null,
70-
onMouseDown,
71-
containerSize = 20,
72-
containerBorderRadius = 4,
73-
caretSize = 14,
74-
onPress,
75-
accessibilityLabel,
76-
shouldStopMouseDownPropagation,
77-
shouldSelectOnPressEnter,
78-
wrapperStyle,
79-
}: CheckboxProps,
80-
ref: ForwardedRef<View>,
81-
) {
65+
function Checkbox({
66+
isChecked = false,
67+
isIndeterminate = false,
68+
hasError = false,
69+
disabled = false,
70+
style,
71+
containerStyle,
72+
children = null,
73+
onMouseDown,
74+
containerSize = 20,
75+
containerBorderRadius = 4,
76+
caretSize = 14,
77+
onPress,
78+
accessibilityLabel,
79+
shouldStopMouseDownPropagation,
80+
shouldSelectOnPressEnter,
81+
wrapperStyle,
82+
ref,
83+
}: CheckboxProps) {
8284
const theme = useTheme();
8385
const styles = useThemeStyles();
8486
const StyleUtils = useStyleUtils();
@@ -117,7 +119,7 @@ function Checkbox(
117119
}
118120
onMouseDown?.(e);
119121
}}
120-
ref={ref}
122+
ref={ref as PressableRef}
121123
style={[StyleUtils.getCheckboxPressableStyle(containerBorderRadius + 2), style]} // to align outline on focus, border-radius of pressable should be 2px more than Checkbox
122124
onKeyDown={handleSpaceOrEnterKey}
123125
role={CONST.ROLE.CHECKBOX}
@@ -157,6 +159,6 @@ function Checkbox(
157159

158160
Checkbox.displayName = 'Checkbox';
159161

160-
export default forwardRef(Checkbox);
162+
export default Checkbox;
161163

162164
export type {CheckboxProps};
Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
import type {ForwardedRef} from 'react';
2-
import React, {forwardRef} from 'react';
3-
import type {ViewProps} from 'react-native';
1+
import React from 'react';
42
import {View} from 'react-native';
3+
import type {FormElementProps} from './index';
54

6-
function FormElement(props: ViewProps, ref: ForwardedRef<View>) {
5+
function FormElement({ref, ...props}: FormElementProps) {
76
return (
87
<View
98
ref={ref}
@@ -15,4 +14,4 @@ function FormElement(props: ViewProps, ref: ForwardedRef<View>) {
1514

1615
FormElement.displayName = 'FormElement';
1716

18-
export default forwardRef(FormElement);
17+
export default FormElement;

src/components/FormElement/index.tsx

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,24 @@
11
import type {ForwardedRef} from 'react';
2-
import React, {forwardRef, useEffect, useRef} from 'react';
2+
import React, {useEffect, useRef} from 'react';
33
import type {ViewProps} from 'react-native';
44
import {View} from 'react-native';
5-
import * as ComponentUtils from '@libs/ComponentUtils';
5+
import {ACCESSIBILITY_ROLE_FORM} from '@libs/ComponentUtils/index';
66
import mergeRefs from '@libs/mergeRefs';
77

8+
type FormElementProps = ViewProps & {
9+
ref?: ForwardedRef<View>;
10+
};
11+
812
const preventFormDefault = (event: SubmitEvent) => {
913
// When Enter is pressed, the form is submitted to the action URL (POST /).
1014
// As we are using a controlled component, we need to disable this behavior here.
1115
event.preventDefault();
1216
};
1317

14-
function FormElement(props: ViewProps, outerRef: ForwardedRef<View>) {
18+
function FormElement({ref, ...props}: FormElementProps) {
1519
const formRef = useRef<HTMLFormElement & View>(null);
1620
// eslint-disable-next-line react-compiler/react-compiler
17-
const mergedRef = mergeRefs(formRef, outerRef);
21+
const mergedRef = mergeRefs(formRef, ref);
1822

1923
useEffect(() => {
2024
const formCurrent = formRef.current;
@@ -38,7 +42,7 @@ function FormElement(props: ViewProps, outerRef: ForwardedRef<View>) {
3842

3943
return (
4044
<View
41-
role={ComponentUtils.ACCESSIBILITY_ROLE_FORM}
45+
role={ACCESSIBILITY_ROLE_FORM}
4246
ref={mergedRef}
4347
// eslint-disable-next-line react/jsx-props-no-spreading
4448
{...props}
@@ -48,4 +52,6 @@ function FormElement(props: ViewProps, outerRef: ForwardedRef<View>) {
4852

4953
FormElement.displayName = 'FormElement';
5054

51-
export default forwardRef(FormElement);
55+
export default FormElement;
56+
57+
export type {FormElementProps};

src/components/Hoverable/ActiveHoverable.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
/* eslint-disable react-compiler/react-compiler */
2-
import type {Ref} from 'react';
3-
import {cloneElement, forwardRef, useCallback, useEffect, useMemo, useRef, useState} from 'react';
2+
import {cloneElement, useCallback, useEffect, useMemo, useRef, useState} from 'react';
43
import {DeviceEventEmitter} from 'react-native';
54
import useOnyx from '@hooks/useOnyx';
65
import usePrevious from '@hooks/usePrevious';
@@ -16,7 +15,7 @@ type MouseEvents = 'onMouseEnter' | 'onMouseLeave' | 'onMouseMove';
1615

1716
type OnMouseEvents = Record<MouseEvents, (e: React.MouseEvent) => void>;
1817

19-
function ActiveHoverable({onHoverIn, onHoverOut, shouldHandleScroll, shouldFreezeCapture, children}: ActiveHoverableProps, outerRef: Ref<HTMLElement>) {
18+
function ActiveHoverable({onHoverIn, onHoverOut, shouldHandleScroll, shouldFreezeCapture, children, ref}: ActiveHoverableProps) {
2019
const [isHovered, setIsHovered] = useState(false);
2120
const elementRef = useRef<HTMLElement | null>(null);
2221
const isScrollingRef = useRef(false);
@@ -111,7 +110,7 @@ function ActiveHoverable({onHoverIn, onHoverOut, shouldHandleScroll, shouldFreez
111110
const {onMouseEnter, onMouseLeave} = child.props as OnMouseEvents;
112111

113112
return cloneElement(child, {
114-
ref: mergeRefs(elementRef, outerRef, child.ref),
113+
ref: mergeRefs(elementRef, ref, child.props.ref),
115114
onMouseEnter: (e: React.MouseEvent) => {
116115
handleMouseEvents('enter')();
117116
onMouseEnter?.(e);
@@ -123,4 +122,4 @@ function ActiveHoverable({onHoverIn, onHoverOut, shouldHandleScroll, shouldFreez
123122
} as React.HTMLAttributes<HTMLElement>);
124123
}
125124

126-
export default forwardRef(ActiveHoverable);
125+
export default ActiveHoverable;

0 commit comments

Comments
 (0)