diff --git a/src/components/HighlightableMenuItem.tsx b/src/components/HighlightableMenuItem.tsx new file mode 100644 index 000000000000..81d2cdaa4646 --- /dev/null +++ b/src/components/HighlightableMenuItem.tsx @@ -0,0 +1,36 @@ +import type {ForwardedRef} from 'react'; +import {forwardRef} from 'react'; +import type {View} from 'react-native'; +import {StyleSheet} from 'react-native'; +import useAnimatedHighlightStyle from '@hooks/useAnimatedHighlightStyle'; +import useThemeStyles from '@hooks/useThemeStyles'; +import MenuItem from './MenuItem'; +import type {MenuItemProps} from './MenuItem'; + +type Props = MenuItemProps & { + highlighted?: boolean; +}; + +function HighlightableMenuItem({wrapperStyle, highlighted, ...restOfProps}: Props, ref: ForwardedRef) { + const styles = useThemeStyles(); + + const flattenedWrapperStyles = StyleSheet.flatten(wrapperStyle); + const animatedHighlightStyle = useAnimatedHighlightStyle({ + shouldHighlight: highlighted ?? false, + height: flattenedWrapperStyles?.height ? Number(flattenedWrapperStyles.height) : styles.sectionMenuItem.height, + borderRadius: flattenedWrapperStyles?.borderRadius ? Number(flattenedWrapperStyles.borderRadius) : styles.sectionMenuItem.borderRadius, + }); + + return ( + // eslint-disable-next-line react/jsx-props-no-spreading + + ); +} + +HighlightableMenuItem.displayName = 'HighlightableMenuItem'; + +export default forwardRef(HighlightableMenuItem); diff --git a/src/components/MenuItem.tsx b/src/components/MenuItem.tsx index 4d3677aa4965..4d6f79bd0196 100644 --- a/src/components/MenuItem.tsx +++ b/src/components/MenuItem.tsx @@ -3,10 +3,9 @@ import type {ImageContentFit} from 'expo-image'; import type {ForwardedRef, ReactNode} from 'react'; import React, {forwardRef, useContext, useMemo} from 'react'; import type {GestureResponderEvent, StyleProp, TextStyle, ViewStyle} from 'react-native'; -import {StyleSheet, View} from 'react-native'; +import {View} from 'react-native'; import type {AnimatedStyle} from 'react-native-reanimated'; import type {ValueOf} from 'type-fest'; -import useAnimatedHighlightStyle from '@hooks/useAnimatedHighlightStyle'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -72,6 +71,9 @@ type MenuItemBaseProps = { /** Used to apply offline styles to child text components */ style?: StyleProp; + /** Outer wrapper styles */ + outerWrapperStyle?: StyleProp; + /** Any additional styles to apply */ wrapperStyle?: StyleProp; @@ -150,9 +152,6 @@ type MenuItemBaseProps = { /** Whether item is focused or active */ focused?: boolean; - /** Whether item is highlighted */ - highlighted?: boolean; - /** Should we disable this menu item? */ disabled?: boolean; @@ -261,6 +260,7 @@ function MenuItem( badgeText, style, wrapperStyle, + outerWrapperStyle, containerStyle, titleStyle, hoverAndPressStyle, @@ -290,7 +290,6 @@ function MenuItem( success = false, focused = false, disabled = false, - highlighted = false, title, subtitle, shouldShowBasicTitle, @@ -330,13 +329,8 @@ function MenuItem( const StyleUtils = useStyleUtils(); const combinedStyle = [style, styles.popoverMenuItem]; const {isSmallScreenWidth} = useWindowDimensions(); - const flattenedWrapperStyles = StyleSheet.flatten(wrapperStyle); - const animatedHighlightStyle = useAnimatedHighlightStyle({ - shouldHighlight: highlighted, - height: flattenedWrapperStyles?.height ? Number(flattenedWrapperStyles.height) : styles.sectionMenuItem.height, - borderRadius: flattenedWrapperStyles?.borderRadius ? Number(flattenedWrapperStyles.borderRadius) : styles.sectionMenuItem.borderRadius, - }); const {isExecuting, singleExecution, waitForNavigate} = useContext(MenuItemGroupContext) ?? {}; + const isDeleted = style && Array.isArray(style) ? style.includes(styles.offlineFeedback.deleted) : false; const descriptionVerticalMargin = shouldShowDescriptionOnTop ? styles.mb1 : styles.mt1; const fallbackAvatarSize = viewMode === CONST.OPTION_MODE.COMPACT ? CONST.AVATAR_SIZE.SMALL : CONST.AVATAR_SIZE.DEFAULT; @@ -436,7 +430,7 @@ function MenuItem( onPressIn={() => shouldBlockSelection && isSmallScreenWidth && DeviceCapabilities.canUseTouchScreen() && ControlSelection.block()} onPressOut={ControlSelection.unblock} onSecondaryInteraction={onSecondaryInteraction} - wrapperStyle={animatedHighlightStyle} + wrapperStyle={outerWrapperStyle} style={({pressed}) => [ containerStyle, diff --git a/src/pages/workspace/WorkspaceInitialPage.tsx b/src/pages/workspace/WorkspaceInitialPage.tsx index 68c5f48e2ff1..6d67b4549f29 100644 --- a/src/pages/workspace/WorkspaceInitialPage.tsx +++ b/src/pages/workspace/WorkspaceInitialPage.tsx @@ -8,8 +8,8 @@ import type {ValueOf} from 'type-fest'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import ConfirmModal from '@components/ConfirmModal'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import HighlightableMenuItem from '@components/HighlightableMenuItem'; import * as Expensicons from '@components/Icon/Expensicons'; -import MenuItem from '@components/MenuItem'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; import ScreenWrapper from '@components/ScreenWrapper'; import ScrollView from '@components/ScrollView'; @@ -278,7 +278,7 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, policyMembers, r In this case where user can click on workspace avatar or menu items, we need to have a check for `isExecuting`. So, we are directly mapping menuItems. */} {menuItems.map((item) => ( -