From 037b3c5557cd155843fe1a5bb8c25232c1476796 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Musia=C5=82?= Date: Tue, 1 Jul 2025 11:36:34 +0200 Subject: [PATCH 1/7] fix PR comments --- Mobile-Expensify | 2 +- src/components/Modal/BaseModal.tsx | 14 +++----------- src/components/Modal/ReanimatedModal/utils.ts | 6 ++++-- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/Mobile-Expensify b/Mobile-Expensify index a3e8c279f4d2..dc4e3a0644e4 160000 --- a/Mobile-Expensify +++ b/Mobile-Expensify @@ -1 +1 @@ -Subproject commit a3e8c279f4d2b303ed18f32fdc88f2b88af4f02d +Subproject commit dc4e3a0644e4663ad2d8c9fc20f217033ec2601f diff --git a/src/components/Modal/BaseModal.tsx b/src/components/Modal/BaseModal.tsx index f01ed4ba6ede..8fcd4d25975c 100644 --- a/src/components/Modal/BaseModal.tsx +++ b/src/components/Modal/BaseModal.tsx @@ -30,7 +30,6 @@ import type ReanimatedModalProps from './ReanimatedModal/types'; import type BaseModalProps from './types'; const REANIMATED_MODAL_TYPES: Array> = [CONST.MODAL.MODAL_TYPE.BOTTOM_DOCKED, CONST.MODAL.MODAL_TYPE.FULLSCREEN]; -const PARTIAL_REANIMATED_MODAL_TYPES: Array> = [CONST.MODAL.MODAL_TYPE.CENTERED_UNSWIPEABLE]; type ModalComponentProps = (ReactNativeModalProps | ReanimatedModalProps) & { type?: ValueOf; @@ -38,16 +37,8 @@ type ModalComponentProps = (ReactNativeModalProps | ReanimatedModalProps) & { }; function ModalComponent({type, shouldUseReanimatedModal, ...props}: ModalComponentProps) { - if (type && REANIMATED_MODAL_TYPES.includes(type)) { - return ( - - ); - } - if (type && PARTIAL_REANIMATED_MODAL_TYPES.includes(type) && shouldUseReanimatedModal) { + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + if ((type && REANIMATED_MODAL_TYPES.includes(type)) || shouldUseReanimatedModal) { return ( ); } + // eslint-disable-next-line react/jsx-props-no-spreading return ; } diff --git a/src/components/Modal/ReanimatedModal/utils.ts b/src/components/Modal/ReanimatedModal/utils.ts index eb9feb3f9054..5442c534882c 100644 --- a/src/components/Modal/ReanimatedModal/utils.ts +++ b/src/components/Modal/ReanimatedModal/utils.ts @@ -23,7 +23,6 @@ function getModalInAnimation(animationType: AnimationInType): ValidKeyframeProps }, }; case 'fadeIn': - default: return { from: {opacity: 0}, to: { @@ -31,6 +30,8 @@ function getModalInAnimation(animationType: AnimationInType): ValidKeyframeProps easing, }, }; + default: + throw new Error('Unknown animation type'); } } @@ -53,7 +54,6 @@ function getModalOutAnimation(animationType: AnimationOutType): ValidKeyframePro }, }; case 'fadeOut': - default: return { from: {opacity: 0.72}, to: { @@ -61,6 +61,8 @@ function getModalOutAnimation(animationType: AnimationOutType): ValidKeyframePro easing, }, }; + default: + throw new Error('Unknown animation type'); } } From 470e4b9ba61e1b182f84e1f1549723509d79dcd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Musia=C5=82?= Date: Tue, 1 Jul 2025 14:29:17 +0200 Subject: [PATCH 2/7] add swipability to reanimated modal, use reanimated modal in search router, fix search router swipe --- .../Container/GestureHandler.tsx | 76 +++++++++++ .../Modal/ReanimatedModal/Container/index.tsx | 22 +++- .../Modal/ReanimatedModal/index.tsx | 5 + src/components/Modal/ReanimatedModal/types.ts | 18 ++- .../Search/SearchRouter/SearchRouter.tsx | 120 ++++++++++-------- .../Search/SearchRouter/SearchRouterModal.tsx | 1 + 6 files changed, 179 insertions(+), 63 deletions(-) create mode 100644 src/components/Modal/ReanimatedModal/Container/GestureHandler.tsx diff --git a/src/components/Modal/ReanimatedModal/Container/GestureHandler.tsx b/src/components/Modal/ReanimatedModal/Container/GestureHandler.tsx new file mode 100644 index 000000000000..426fc95bcaae --- /dev/null +++ b/src/components/Modal/ReanimatedModal/Container/GestureHandler.tsx @@ -0,0 +1,76 @@ +import type {PropsWithChildren} from 'react'; +import React, {useMemo} from 'react'; +import type {GestureStateChangeEvent, GestureType, PanGestureHandlerEventPayload} from 'react-native-gesture-handler'; +import {Gesture, GestureDetector} from 'react-native-gesture-handler'; +import {runOnJS, useSharedValue} from 'react-native-reanimated'; +import type {GestureHandlerProps, SwipeDirection} from '@components/Modal/ReanimatedModal/types'; +import CONST from '@src/CONST'; + +function hasSwipeEnded( + e: GestureStateChangeEvent, + initialPosition: {x: number; y: number}, + swipeThreshold: number, + swipeDirection?: SwipeDirection | SwipeDirection[], + onSwipeComplete?: () => void, +) { + 'worklet'; + + if (!swipeDirection || !onSwipeComplete) { + return; + } + const directions = Array.isArray(swipeDirection) ? swipeDirection : [swipeDirection]; + + for (const direction of directions) { + switch (direction) { + case CONST.SWIPE_DIRECTION.RIGHT: + if (e.translationX - initialPosition.x > swipeThreshold) { + runOnJS(onSwipeComplete)(); + } + break; + case CONST.SWIPE_DIRECTION.LEFT: + if (initialPosition.x - e.translationX > swipeThreshold) { + runOnJS(onSwipeComplete)(); + } + break; + case CONST.SWIPE_DIRECTION.UP: + if (initialPosition.y - e.translationY > swipeThreshold) { + runOnJS(onSwipeComplete)(); + } + break; + case CONST.SWIPE_DIRECTION.DOWN: + if (e.translationY - initialPosition.y > swipeThreshold) { + runOnJS(onSwipeComplete)(); + } + break; + default: + throw new Error('Unknown swipe direction'); + } + } +} + +function GestureHandler({swipeDirection, onSwipeComplete, swipeThreshold = 100, children}: PropsWithChildren) { + const initialTranslationX = useSharedValue(0); + const initialTranslationY = useSharedValue(0); + const panGesture: GestureType = useMemo( + () => + Gesture.Pan() + .onStart((e) => { + initialTranslationX.set(e.translationX); + initialTranslationY.set(e.translationY); + }) + .onEnd((e) => { + hasSwipeEnded(e, {x: initialTranslationX.get(), y: initialTranslationY.get()}, swipeThreshold, swipeDirection, onSwipeComplete); + }), + [initialTranslationX, initialTranslationY, onSwipeComplete, swipeDirection, swipeThreshold], + ); + + if (!swipeDirection || !onSwipeComplete) { + return children; + } + + return {children}; +} + +GestureHandler.displayName = 'GestureHandler'; + +export default GestureHandler; diff --git a/src/components/Modal/ReanimatedModal/Container/index.tsx b/src/components/Modal/ReanimatedModal/Container/index.tsx index 1ab545e50c6b..d9c50b8d9b6d 100644 --- a/src/components/Modal/ReanimatedModal/Container/index.tsx +++ b/src/components/Modal/ReanimatedModal/Container/index.tsx @@ -6,6 +6,7 @@ import type {ContainerProps} from '@components/Modal/ReanimatedModal/types'; import {getModalInAnimation, getModalOutAnimation} from '@components/Modal/ReanimatedModal/utils'; import useThemeStyles from '@hooks/useThemeStyles'; import CONST from '@src/CONST'; +import GestureHandler from './GestureHandler'; function Container({ style, @@ -16,6 +17,9 @@ function Container({ animationIn, animationOut, type, + onSwipeComplete, + swipeDirection, + swipeThreshold = 100, ...props }: Partial & ContainerProps) { const styles = useThemeStyles(); @@ -46,13 +50,19 @@ function Container({ // eslint-disable-next-line react/jsx-props-no-spreading {...props} > - - {props.children} - + + {props.children} + + ); } diff --git a/src/components/Modal/ReanimatedModal/index.tsx b/src/components/Modal/ReanimatedModal/index.tsx index ab873254fc29..db0c3b8b22c6 100644 --- a/src/components/Modal/ReanimatedModal/index.tsx +++ b/src/components/Modal/ReanimatedModal/index.tsx @@ -37,6 +37,9 @@ function ReanimatedModal({ style, type, statusBarTranslucent = false, + onSwipeComplete, + swipeDirection, + swipeThreshold, ...props }: ReanimatedModalProps) { const [isVisibleState, setIsVisibleState] = useState(isVisible); @@ -148,6 +151,8 @@ function ReanimatedModal({ animationOut={animationOut as AnimationOutType} style={style} type={type} + onSwipeComplete={onSwipeComplete} + swipeDirection={swipeDirection} > {children} diff --git a/src/components/Modal/ReanimatedModal/types.ts b/src/components/Modal/ReanimatedModal/types.ts index cf03deb66340..dbcc19ae82df 100644 --- a/src/components/Modal/ReanimatedModal/types.ts +++ b/src/components/Modal/ReanimatedModal/types.ts @@ -13,13 +13,27 @@ type GestureProps = { deviceWidth?: number | null; }; +type SwipeDirection = ValueOf; + +type GestureHandlerProps = { + /** Callback to be fired on swipe gesture. */ + onSwipeComplete?: () => void; + + /** Threshold for swipe gesture. */ + swipeThreshold: number; + + /** Threshold for swipe gesture. */ + swipeDirection?: SwipeDirection | SwipeDirection[]; +}; + type AnimationInType = 'fadeIn' | 'slideInUp' | 'slideInRight'; type AnimationOutType = 'fadeOut' | 'slideOutDown' | 'slideOutRight'; type AnimationOut = ValueOf>; type ReanimatedModalProps = ViewProps & - GestureProps & { + GestureProps & + GestureHandlerProps & { /** Content inside the modal */ children: ReactNode; @@ -168,4 +182,4 @@ type ContainerProps = { }; export default ReanimatedModalProps; -export type {BackdropProps, ContainerProps, AnimationOut, AnimationInType, AnimationOutType}; +export type {BackdropProps, ContainerProps, GestureHandlerProps, AnimationOut, AnimationInType, AnimationOutType, SwipeDirection}; diff --git a/src/components/Search/SearchRouter/SearchRouter.tsx b/src/components/Search/SearchRouter/SearchRouter.tsx index 543c7e3f8045..3fa852d6db79 100644 --- a/src/components/Search/SearchRouter/SearchRouter.tsx +++ b/src/components/Search/SearchRouter/SearchRouter.tsx @@ -3,7 +3,9 @@ import {deepEqual} from 'fast-equals'; import React, {forwardRef, useCallback, useEffect, useRef, useState} from 'react'; import type {TextInputProps} from 'react-native'; import {InteractionManager, Keyboard, View} from 'react-native'; +import {Gesture, GestureDetector} from 'react-native-gesture-handler'; import {useOnyx} from 'react-native-onyx'; +import {runOnJS} from 'react-native-reanimated'; import type {ValueOf} from 'type-fest'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Expensicons from '@components/Icon/Expensicons'; @@ -318,63 +320,71 @@ function SearchRouter({onRouterClose, shouldHideInputCaret, isSearchRouterDispla const modalWidth = shouldUseNarrowLayout ? styles.w100 : {width: variables.searchRouterPopoverWidth}; const isRecentSearchesDataLoaded = !isLoadingOnyxValue(recentSearchesMetadata); + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const tap = Gesture.Tap().onFinalize(() => { + 'worklet'; + + runOnJS(() => { + Keyboard.dismiss(); + })(); + }); return ( - true} - onResponderRelease={Keyboard.dismiss} - > - {shouldUseNarrowLayout && ( - onRouterClose()} - shouldDisplayHelpButton={false} - /> - )} - {isRecentSearchesDataLoaded && ( - <> - { - const focusedOption = listRef.current?.getFocusedOption(); - - if (!focusedOption) { - submitSearch(textInputValue); - return; - } - - onListItemPress(focusedOption); - }} - caretHidden={shouldHideInputCaret} - autocompleteListRef={listRef} - shouldShowOfflineMessage - wrapperStyle={{...styles.border, ...styles.alignItemsCenter}} - outerWrapperStyle={[shouldUseNarrowLayout ? styles.mv3 : styles.mv2, shouldUseNarrowLayout ? styles.mh5 : styles.mh2]} - wrapperFocusedStyle={styles.borderColorFocus} - isSearchingForReports={isSearchingForReports} - selection={selection} - substitutionMap={autocompleteSubstitutions} - ref={textInputRef} - /> - listRef.current?.updateAndScrollToFocusedIndex(1)} - ref={listRef} - textInputRef={textInputRef} + + + {shouldUseNarrowLayout && ( + onRouterClose()} + shouldDisplayHelpButton={false} /> - - )} - + )} + {isRecentSearchesDataLoaded && ( + <> + { + const focusedOption = listRef.current?.getFocusedOption(); + + if (!focusedOption) { + submitSearch(textInputValue); + return; + } + + onListItemPress(focusedOption); + }} + caretHidden={shouldHideInputCaret} + autocompleteListRef={listRef} + shouldShowOfflineMessage + wrapperStyle={{...styles.border, ...styles.alignItemsCenter}} + outerWrapperStyle={[shouldUseNarrowLayout ? styles.mv3 : styles.mv2, shouldUseNarrowLayout ? styles.mh5 : styles.mh2]} + wrapperFocusedStyle={styles.borderColorFocus} + isSearchingForReports={isSearchingForReports} + selection={selection} + substitutionMap={autocompleteSubstitutions} + ref={textInputRef} + /> + listRef.current?.updateAndScrollToFocusedIndex(1)} + ref={listRef} + textInputRef={textInputRef} + /> + + )} + + ); } diff --git a/src/components/Search/SearchRouter/SearchRouterModal.tsx b/src/components/Search/SearchRouter/SearchRouterModal.tsx index c4a6b5d128bf..232b1bf2fb53 100644 --- a/src/components/Search/SearchRouter/SearchRouterModal.tsx +++ b/src/components/Search/SearchRouter/SearchRouterModal.tsx @@ -35,6 +35,7 @@ function SearchRouterModal() { onModalShow={() => setShouldHideInputCaret(false)} shouldApplySidePanelOffset={!shouldUseNarrowLayout} enableEdgeToEdgeBottomSafeAreaPadding + shouldUseReanimatedModal > Date: Tue, 1 Jul 2025 15:39:57 +0200 Subject: [PATCH 3/7] only enable ReanimatedModal on small screens --- src/components/Search/SearchRouter/SearchRouterModal.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Search/SearchRouter/SearchRouterModal.tsx b/src/components/Search/SearchRouter/SearchRouterModal.tsx index 232b1bf2fb53..ef93bb0188f7 100644 --- a/src/components/Search/SearchRouter/SearchRouterModal.tsx +++ b/src/components/Search/SearchRouter/SearchRouterModal.tsx @@ -20,7 +20,7 @@ function SearchRouterModal() { const [shouldHideInputCaret, setShouldHideInputCaret] = useState(isMobileWebIOS); const modalType = shouldUseNarrowLayout ? CONST.MODAL.MODAL_TYPE.CENTERED_SWIPEABLE_TO_RIGHT : CONST.MODAL.MODAL_TYPE.POPOVER; - + // For now were only enabling shouldUseReanimatedModal narrow layouts. On wide ones it's a popover and it is not migrated yet. return ( setShouldHideInputCaret(false)} shouldApplySidePanelOffset={!shouldUseNarrowLayout} enableEdgeToEdgeBottomSafeAreaPadding - shouldUseReanimatedModal + shouldUseReanimatedModal={shouldUseNarrowLayout} > Date: Tue, 1 Jul 2025 16:17:03 +0200 Subject: [PATCH 4/7] use animation utils for web backdrop --- .../ReanimatedModal/Backdrop/index.web.tsx | 21 ++++--------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/src/components/Modal/ReanimatedModal/Backdrop/index.web.tsx b/src/components/Modal/ReanimatedModal/Backdrop/index.web.tsx index 6341e86862a5..eb16947866d5 100644 --- a/src/components/Modal/ReanimatedModal/Backdrop/index.web.tsx +++ b/src/components/Modal/ReanimatedModal/Backdrop/index.web.tsx @@ -1,15 +1,14 @@ import React, {useMemo} from 'react'; import {View} from 'react-native'; -import Animated, {Easing, Keyframe} from 'react-native-reanimated'; +import Animated, {Keyframe} from 'react-native-reanimated'; import type {BackdropProps} from '@components/Modal/ReanimatedModal/types'; +import {getModalInAnimation, getModalOutAnimation} from '@components/Modal/ReanimatedModal/utils'; import {PressableWithoutFeedback} from '@components/Pressable'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import variables from '@styles/variables'; import CONST from '@src/CONST'; -const easing = Easing.bezier(0.76, 0.0, 0.24, 1.0).factory(); - function Backdrop({ style, customBackdrop, @@ -23,25 +22,13 @@ function Backdrop({ const {translate} = useLocalize(); const Entering = useMemo(() => { - const FadeIn = new Keyframe({ - from: {opacity: 0}, - to: { - opacity: 0.72, - easing, - }, - }); + const FadeIn = new Keyframe(getModalInAnimation('fadeIn')); return FadeIn.duration(animationInTiming); }, [animationInTiming]); const Exiting = useMemo(() => { - const FadeOut = new Keyframe({ - from: {opacity: 0.72}, - to: { - opacity: 0, - easing, - }, - }); + const FadeOut = new Keyframe(getModalOutAnimation('fadeOut')); return FadeOut.duration(animationOutTiming); }, [animationOutTiming]); From 30e17afe10317722a8d6d1d1e07e6d047917a063 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Musia=C5=82?= Date: Thu, 3 Jul 2025 15:42:05 +0200 Subject: [PATCH 5/7] was crashing otherwise --- src/components/Search/SearchRouter/SearchRouter.tsx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/components/Search/SearchRouter/SearchRouter.tsx b/src/components/Search/SearchRouter/SearchRouter.tsx index 9cfb64277a01..696f3efb376d 100644 --- a/src/components/Search/SearchRouter/SearchRouter.tsx +++ b/src/components/Search/SearchRouter/SearchRouter.tsx @@ -429,14 +429,16 @@ function SearchRouter({onRouterClose, shouldHideInputCaret, isSearchRouterDispla const modalWidth = shouldUseNarrowLayout ? styles.w100 : {width: variables.searchRouterPopoverWidth}; const isRecentSearchesDataLoaded = !isLoadingOnyxValue(recentSearchesMetadata); - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const dismissKeyboard = () => { + Keyboard.dismiss(); + }; + const tap = Gesture.Tap().onFinalize(() => { 'worklet'; - runOnJS(() => { - Keyboard.dismiss(); - })(); + runOnJS(dismissKeyboard)(); }); + return ( Date: Tue, 8 Jul 2025 16:19:16 +0200 Subject: [PATCH 6/7] fix PR comments --- .../Container/GestureHandler.tsx | 6 +- .../Search/SearchRouter/SearchRouter.tsx | 126 ++++++++---------- 2 files changed, 63 insertions(+), 69 deletions(-) diff --git a/src/components/Modal/ReanimatedModal/Container/GestureHandler.tsx b/src/components/Modal/ReanimatedModal/Container/GestureHandler.tsx index 426fc95bcaae..a03aa2582e71 100644 --- a/src/components/Modal/ReanimatedModal/Container/GestureHandler.tsx +++ b/src/components/Modal/ReanimatedModal/Container/GestureHandler.tsx @@ -15,7 +15,8 @@ function hasSwipeEnded( ) { 'worklet'; - if (!swipeDirection || !onSwipeComplete) { + // eslint-disable-next-line @typescript-eslint/prefer-optional-chain + if (!swipeDirection || !swipeDirection?.length || !onSwipeComplete) { return; } const directions = Array.isArray(swipeDirection) ? swipeDirection : [swipeDirection]; @@ -64,7 +65,8 @@ function GestureHandler({swipeDirection, onSwipeComplete, swipeThreshold = 100, [initialTranslationX, initialTranslationY, onSwipeComplete, swipeDirection, swipeThreshold], ); - if (!swipeDirection || !onSwipeComplete) { + // eslint-disable-next-line @typescript-eslint/prefer-optional-chain + if (!swipeDirection || !swipeDirection?.length || !onSwipeComplete) { return children; } diff --git a/src/components/Search/SearchRouter/SearchRouter.tsx b/src/components/Search/SearchRouter/SearchRouter.tsx index c36106619378..fff9c46b90be 100644 --- a/src/components/Search/SearchRouter/SearchRouter.tsx +++ b/src/components/Search/SearchRouter/SearchRouter.tsx @@ -3,8 +3,7 @@ import {deepEqual} from 'fast-equals'; import React, {forwardRef, useCallback, useEffect, useRef, useState} from 'react'; import type {TextInputProps} from 'react-native'; import {InteractionManager, Keyboard, View} from 'react-native'; -import {Gesture, GestureDetector} from 'react-native-gesture-handler'; -import {runOnJS} from 'react-native-reanimated'; +import {Gesture, GestureDetector, GestureHandlerRootView} from 'react-native-gesture-handler'; import type {ValueOf} from 'type-fest'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Expensicons from '@components/Icon/Expensicons'; @@ -429,73 +428,66 @@ function SearchRouter({onRouterClose, shouldHideInputCaret, isSearchRouterDispla const modalWidth = shouldUseNarrowLayout ? styles.w100 : {width: variables.searchRouterPopoverWidth}; const isRecentSearchesDataLoaded = !isLoadingOnyxValue(recentSearchesMetadata); - const dismissKeyboard = () => { - Keyboard.dismiss(); - }; - - const tap = Gesture.Tap().onFinalize(() => { - 'worklet'; - - runOnJS(dismissKeyboard)(); - }); - return ( - - - {shouldUseNarrowLayout && ( - onRouterClose()} - shouldDisplayHelpButton={false} - /> - )} - {isRecentSearchesDataLoaded && ( - <> - { - const focusedOption = listRef.current?.getFocusedOption(); - - if (!focusedOption) { - submitSearch(textInputValue); - return; - } - - onListItemPress(focusedOption); - }} - caretHidden={shouldHideInputCaret} - autocompleteListRef={listRef} - shouldShowOfflineMessage - wrapperStyle={{...styles.border, ...styles.alignItemsCenter}} - outerWrapperStyle={[shouldUseNarrowLayout ? styles.mv3 : styles.mv2, shouldUseNarrowLayout ? styles.mh5 : styles.mh2]} - wrapperFocusedStyle={styles.borderColorFocus} - isSearchingForReports={isSearchingForReports} - selection={selection} - substitutionMap={autocompleteSubstitutions} - ref={textInputRef} - /> - listRef.current?.updateAndScrollToFocusedIndex(1)} - ref={listRef} - textInputRef={textInputRef} + + + {' '} + + {shouldUseNarrowLayout && ( + onRouterClose()} + shouldDisplayHelpButton={false} /> - - )} - - + )} + {isRecentSearchesDataLoaded && ( + <> + { + const focusedOption = listRef.current?.getFocusedOption(); + + if (!focusedOption) { + submitSearch(textInputValue); + return; + } + + onListItemPress(focusedOption); + }} + caretHidden={shouldHideInputCaret} + autocompleteListRef={listRef} + shouldShowOfflineMessage + wrapperStyle={{...styles.border, ...styles.alignItemsCenter}} + outerWrapperStyle={[shouldUseNarrowLayout ? styles.mv3 : styles.mv2, shouldUseNarrowLayout ? styles.mh5 : styles.mh2]} + wrapperFocusedStyle={styles.borderColorFocus} + isSearchingForReports={isSearchingForReports} + selection={selection} + substitutionMap={autocompleteSubstitutions} + ref={textInputRef} + /> + listRef.current?.updateAndScrollToFocusedIndex(1)} + ref={listRef} + textInputRef={textInputRef} + /> + + )} + + + ); } From cff2bd9a1a3954d5ce64bdb2be14552ed9775c4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Musia=C5=82?= Date: Tue, 8 Jul 2025 16:28:33 +0200 Subject: [PATCH 7/7] remove typo --- src/components/Search/SearchRouter/SearchRouter.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/Search/SearchRouter/SearchRouter.tsx b/src/components/Search/SearchRouter/SearchRouter.tsx index fff9c46b90be..131d54416d95 100644 --- a/src/components/Search/SearchRouter/SearchRouter.tsx +++ b/src/components/Search/SearchRouter/SearchRouter.tsx @@ -431,7 +431,6 @@ function SearchRouter({onRouterClose, shouldHideInputCaret, isSearchRouterDispla return ( - {' '}