Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@ import type {SearchColumnType, TableColumnSize} from '@components/Search/types';
import TransactionItemRow from '@components/TransactionItemRow';
import {useEditingCellState} from '@components/TransactionItemRow/EditableCell';

import useAnimatedHighlightStyle from '@hooks/useAnimatedHighlightStyle';
import useLocalize from '@hooks/useLocalize';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useResponsiveLayoutOnWideRHP from '@hooks/useResponsiveLayoutOnWideRHP';
import useRowHighlightAnimation from '@hooks/useRowHighlightAnimation';
import useStyleUtils from '@hooks/useStyleUtils';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import useTransactionInlineEdit from '@hooks/useTransactionInlineEdit';

Expand Down Expand Up @@ -95,7 +94,7 @@ type MoneyRequestReportTransactionItemBodyProps = Omit<MoneyRequestReportTransac
inlineEdit?: InlineEditValues;

/** Highlight animation style, computed by the parent so its state survives the narrow↔wide swap on resize. */
animatedHighlightStyle: ReturnType<typeof useAnimatedHighlightStyle>;
animatedHighlightStyle: ReturnType<typeof useRowHighlightAnimation>;

shouldSkipDeferRBR?: boolean;
};
Expand Down Expand Up @@ -318,17 +317,14 @@ function MoneyRequestReportTransactionItem(props: MoneyRequestReportTransactionI
const {shouldBeHighlighted} = props;
const {isMediumScreenWidth} = useResponsiveLayout();
const {shouldUseNarrowLayout} = useResponsiveLayoutOnWideRHP();
const theme = useTheme();
// Mirrors the layout check inside TransactionItemRow so the narrow body never pays for useTransactionInlineEdit.
const isNarrowLayout = shouldUseNarrowLayout || (isMediumScreenWidth && !props.shouldScrollHorizontally);

// Hoisted out of the body so the highlight animation timeline survives the narrow↔wide
// component-type swap caused by browser resize.
const animatedHighlightStyle = useAnimatedHighlightStyle({
borderRadius: shouldUseNarrowLayout ? variables.componentBorderRadius : 0,
const animatedHighlightStyle = useRowHighlightAnimation({
shouldHighlight: shouldBeHighlighted,
highlightColor: theme.messageHighlightBG,
backgroundColor: theme.highlightBG,
borderRadius: shouldUseNarrowLayout ? variables.componentBorderRadius : 0,
shouldApplyOtherStyles: !shouldUseNarrowLayout,
});

Expand Down
4 changes: 1 addition & 3 deletions src/components/Search/SearchAutocompleteList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ function SearchRouterItem(props: UserListItemProps<AutocompleteListItem> | Searc
return <SearchQueryListItem {...props} />;
}

const {item, isFocused, showTooltip, isDisabled, onSelectRow, onDismissError, shouldPreventEnterKeySubmit, rightHandSideComponent, onFocus, shouldSyncFocus, wrapperStyle} = props;
const {item, isFocused, showTooltip, isDisabled, onSelectRow, onDismissError, shouldPreventEnterKeySubmit, onFocus, shouldSyncFocus, wrapperStyle} = props;
const fsClass = FS.getChatFSClass((item as SearchOption<Report> | undefined)?.item);

return (
Expand All @@ -153,7 +153,6 @@ function SearchRouterItem(props: UserListItemProps<AutocompleteListItem> | Searc
onSelectRow={onSelectRow}
onDismissError={onDismissError}
shouldPreventEnterKeySubmit={shouldPreventEnterKeySubmit}
rightHandSideComponent={rightHandSideComponent}
onFocus={onFocus}
shouldSyncFocus={shouldSyncFocus}
wrapperStyle={wrapperStyle}
Expand Down Expand Up @@ -535,7 +534,6 @@ function SearchAutocompleteList({
keyForList,
pressableStyle: styles.br2,
text: StringUtils.lineBreaksToSpaces(shouldParserToHTML ? Parser.htmlToText(option.text ?? '') : (option.text ?? '')),
wrapperStyle: [styles.pr3, styles.pl3],
} as AutocompleteListItem;
});

Expand Down
44 changes: 24 additions & 20 deletions src/components/Search/SearchList/ListItem/ChatListItem.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {useRowSelection} from '@components/Search/SearchSelectionProvider';
import BaseListItem from '@components/SelectionList/ListItem/BaseListItem';
import {useListItemHighlight} from '@components/SelectionList/ListItemComposed';
import ListItemComposed from '@components/SelectionList/ListItemComposed';
import useListItemHighlight from '@components/SelectionList/ListItemComposed/hooks/useListItemHighlight';
import type {ListItem} from '@components/SelectionList/types';

import useOnyx from '@hooks/useOnyx';
Expand All @@ -15,6 +15,7 @@ import ONYXKEYS from '@src/ONYXKEYS';
import {getStableReportSelector} from '@src/selectors/Report';

import React from 'react';
import {View} from 'react-native';

import type {ChatListItemProps, ReportActionListItemType} from './types';

Expand Down Expand Up @@ -49,14 +50,13 @@ function ChatListItem<TItem extends ListItem>({
const handlePress = () => onSelectRow(item);

return (
<BaseListItem
<ListItemComposed
item={item}
pressableStyle={[pressableStyle, styles.p0, styles.textAlignLeft, styles.overflowHidden, item.cursorStyle]}
wrapperStyle={[styles.flex1, styles.justifyContentBetween, styles.userSelectNone]}
containerStyle={styles.mb2}
isFocused={isFocused}
isDisabled={isDisabled}
showTooltip={showTooltip}
shouldShowTooltip={showTooltip}
canSelectMultiple={canSelectMultiple}
onLongPressRow={onLongPressRow}
onSelectRow={onSelectRow}
Expand All @@ -65,22 +65,26 @@ function ChatListItem<TItem extends ListItem>({
shouldSyncFocus={shouldSyncFocus}
pressableWrapperStyle={pressableWrapperStyle}
hoverStyle={isSelected && styles.activeComponentBG}
forwardedFSClass={fsClass}
>
<ReportActionItem
action={reportActionItem}
report={reportStable}
transactionThreadReport={transactionThreadReport}
chatReport={chatReportStable}
onPress={handlePress}
parentReportAction={undefined}
displayAsGroup={false}
shouldDisplayNewMarker={false}
isFirstVisibleReportAction={false}
shouldDisplayContextMenu={false}
shouldShowBorder
/>
</BaseListItem>
<View
style={[styles.flex1, styles.justifyContentBetween, styles.userSelectNone]}
fsClass={fsClass}
>
<ReportActionItem
action={reportActionItem}
report={reportStable}
transactionThreadReport={transactionThreadReport}
chatReport={chatReportStable}
onPress={handlePress}
parentReportAction={undefined}
displayAsGroup={false}
shouldDisplayNewMarker={false}
isFirstVisibleReportAction={false}
shouldDisplayContextMenu={false}
shouldShowBorder
/>
</View>
</ListItemComposed>
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,10 @@ import {
useSearchSubmitPopoverGuard,
} from '@components/ReportSubmitToPopoverAnchor';
import {useSearchQueryContext, useSearchResultsContext} from '@components/Search/SearchContext';
import BaseListItem from '@components/SelectionList/ListItem/BaseListItem';
import ListItemComposed from '@components/SelectionList/ListItemComposed';
import type {ListItem} from '@components/SelectionList/types';
import Text from '@components/Text';

import useAnimatedHighlightStyle from '@hooks/useAnimatedHighlightStyle';
import useConfirmModal from '@hooks/useConfirmModal';
import {useCurrencyListActions} from '@hooks/useCurrencyList';
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
Expand All @@ -22,6 +21,7 @@ import useLocalize from '@hooks/useLocalize';
import useOnyx from '@hooks/useOnyx';
import {useReportPaymentContext} from '@hooks/usePaymentContext';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useRowHighlightAnimation from '@hooks/useRowHighlightAnimation';
import useStyleUtils from '@hooks/useStyleUtils';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
Expand Down Expand Up @@ -379,24 +379,14 @@ function ExpenseReportListItemInner<TItem extends ListItem>({
[styles, isSelected, isLargeScreenWidth, isFirstItem, isLastItem, isPendingDelete, StyleUtils],
);

const listItemWrapperStyle = useMemo(
() => [
styles.flex1,
styles.userSelectNone,
isLargeScreenWidth ? {...styles.flexRow, ...styles.justifyContentBetween, ...styles.alignItemsCenter} : {...styles.flexColumn, ...styles.alignItemsStretch},
],
[styles, isLargeScreenWidth],
);

// The animated style is applied inline, so the `borderRadius: 0` it carries wins over the static
// `tableTopRadius`/`tableBottomRadius` below and squares off the list's outer corners. Skip it for the first
// and last rows only, so every other row keeps its existing (already square) behavior.
const shouldApplyAnimatedBorderRadius = !isLargeScreenWidth && !isFirstItem && !isLastItem;
const animatedHighlightStyle = useAnimatedHighlightStyle({
borderRadius: 0,
const animatedHighlightStyle = useRowHighlightAnimation({
shouldHighlight: item?.shouldAnimateInHighlight ?? false,
highlightColor: theme.messageHighlightBG,
backgroundColor: isSelected ? theme.activeComponentBG : theme.highlightBG,
isSelected,
borderRadius: 0,
shouldApplyOtherStyles: shouldApplyAnimatedBorderRadius,
});

Expand Down Expand Up @@ -478,17 +468,16 @@ function ExpenseReportListItemInner<TItem extends ListItem>({

// Keep nested controls reachable: a group on web, and accessible={false} on iOS (which otherwise collapses children).
return (
<BaseListItem
<ListItemComposed
item={item}
isSelected={isSelected}
accessible={canSelectMultiple && shouldBreakAccessibilityGrouping() ? false : undefined}
accessibilityRole={canSelectMultiple ? CONST.ROLE.GROUP : undefined}
accessibilityLabel={rowAccessibilityLabel}
shouldUseOptionRole={false}
pressableStyle={listItemPressableStyle}
wrapperStyle={listItemWrapperStyle}
isFocused={isFocused}
showTooltip={showTooltip}
shouldShowTooltip={showTooltip}
canSelectMultiple={canSelectMultiple}
onSelectRow={onSelectRow}
onFocus={onFocus}
Expand All @@ -507,41 +496,36 @@ function ExpenseReportListItemInner<TItem extends ListItem>({
isDisabled={isPendingDelete}
shouldDisableHoverStyle={isPendingDelete}
>
{(hovered) => (
<View style={[styles.flex1]}>
{!isLargeScreenWidth && (
<UserInfoAndActionButtonRow
item={liveReportItem}
shouldShowUserInfo={!!reportItem?.from}
stateNum={reportItem.stateNum}
statusNum={reportItem.statusNum}
isSelected={isSelected}
/>
)}
<AvatarTooltipsProvider isEnabled={showTooltip}>
<ExpenseReportListItemRow
item={liveReportItem}
columns={columns}
reportActions={reportActions}
isActionLoading={isActionLoading ?? isLoading}
canSelectMultiple={canSelectMultiple}
onCheckboxPress={handleSelectionButtonPress}
onButtonPress={handleOnButtonPress}
chatReport={chatReport}
isSelectAllChecked={isSelected}
isIndeterminate={isIndeterminate}
isDisabledCheckbox={isDisabledCheckbox}
isHovered={hovered}
isFocused={isFocused}
isPendingDelete={isPendingDelete}
shouldDisableActionPointerEvents={shouldDisableSearchSubmitPress}
shouldShowMarkAsDoneCopy={shouldShowMarkAsDoneCopy}
/>
</AvatarTooltipsProvider>
{getDescription}
</View>
)}
</BaseListItem>
<View style={[styles.flex1, styles.userSelectNone]}>
{!isLargeScreenWidth && (
<UserInfoAndActionButtonRow
item={liveReportItem}
shouldShowUserInfo={!!reportItem?.from}
stateNum={reportItem.stateNum}
statusNum={reportItem.statusNum}
isSelected={isSelected}
/>
)}
<AvatarTooltipsProvider isEnabled={showTooltip}>
<ExpenseReportListItemRow
item={liveReportItem}
columns={columns}
reportActions={reportActions}
isActionLoading={isActionLoading ?? isLoading}
canSelectMultiple={canSelectMultiple}
onCheckboxPress={handleSelectionButtonPress}
onButtonPress={handleOnButtonPress}
chatReport={chatReport}
isSelectAllChecked={isSelected}
isIndeterminate={isIndeterminate}
isDisabledCheckbox={isDisabledCheckbox}
shouldDisableActionPointerEvents={shouldDisableSearchSubmitPress}
shouldShowMarkAsDoneCopy={shouldShowMarkAsDoneCopy}
/>
</AvatarTooltipsProvider>
{getDescription}
</View>
</ListItemComposed>
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import SingleAvatar from '@components/Avatar/layouts/SingleAvatar';
import SubscriptAvatar from '@components/Avatar/layouts/SubscriptAvatar';
import type {ExpenseReportListItemType} from '@components/Search/SearchList/ListItem/types';
import {useRowSelection} from '@components/Search/SearchSelectionProvider';
import {useListItemContext, useListItemHovered} from '@components/SelectionList/ListItemContext';

import useStyleUtils from '@hooks/useStyleUtils';
import useTheme from '@hooks/useTheme';
Expand All @@ -16,27 +17,27 @@ import {View} from 'react-native';

type ExpenseReportListItemAvatarProps = {
item: ExpenseReportListItemType;
isHovered?: boolean;
isFocused?: boolean;
isLargeScreenWidth?: boolean;
};

function ExpenseReportListItemAvatar({item, isHovered = false, isFocused = false, isLargeScreenWidth = false}: ExpenseReportListItemAvatarProps) {
/** The report avatar cell of the wide (table) expense report row. */
function ExpenseReportListItemAvatar({item}: ExpenseReportListItemAvatarProps) {
const StyleUtils = useStyleUtils();
const styles = useThemeStyles();
const theme = useTheme();

const {isSelected} = useRowSelection(item.keyForList);
const {isFocusVisible} = useListItemContext();
const isHovered = useListItemHovered();
const finalAvatarBorderColor =
StyleUtils.getItemBackgroundColorStyle(isSelected, isFocused || isHovered, !!item.isDisabled, theme.activeComponentBG, theme.hoverComponentBG)?.backgroundColor ?? theme.highlightBG;
StyleUtils.getItemBackgroundColorStyle(isSelected, isFocusVisible || isHovered, !!item.isDisabled, theme.activeComponentBG, theme.hoverComponentBG)?.backgroundColor ??
theme.highlightBG;

// Without a primary avatar there is nothing to anchor the row on, and compacting the array would promote the secondary avatar into the primary slot.
if (!item.primaryAvatar) {
return null;
}

const icons = item.secondaryAvatar ? [item.primaryAvatar, item.secondaryAvatar] : [item.primaryAvatar];
const avatarSize = isLargeScreenWidth ? CONST.AVATAR_SIZE.SMALL : CONST.AVATAR_SIZE.DEFAULT;
const {layout, primaryIcon, secondaryIcon} = getAvatarLayout({icons, avatarType: item.avatarType});

let avatarContent;
Expand All @@ -45,14 +46,14 @@ function ExpenseReportListItemAvatar({item, isHovered = false, isFocused = false
<SubscriptAvatar
primaryAvatar={primaryIcon}
secondaryAvatar={secondaryIcon}
size={avatarSize}
size={CONST.AVATAR_SIZE.SMALL}
backdropColor={finalAvatarBorderColor}
/>
);
} else if (layout === CONST.REPORT_ACTION_AVATARS.TYPE.MULTIPLE_DIAGONAL) {
avatarContent = (
<DiagonalAvatars
size={avatarSize}
size={CONST.AVATAR_SIZE.SMALL}
icons={icons}
isInReportAction={false}
/>
Expand All @@ -61,8 +62,8 @@ function ExpenseReportListItemAvatar({item, isHovered = false, isFocused = false
avatarContent = (
<SingleAvatar
avatar={item.primaryAvatar}
size={avatarSize}
containerStyles={StyleUtils.getContainerStyles(avatarSize)}
size={CONST.AVATAR_SIZE.SMALL}
containerStyles={StyleUtils.getContainerStyles(CONST.AVATAR_SIZE.SMALL)}
/>
);
}
Expand Down
Loading
Loading