Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactored selection list items #38448

Merged
merged 13 commits into from
Apr 2, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ function YearPickerModal({isVisible, years, currentYear = new Date().getFullYear
onBackButtonPress={onClose}
/>
<SelectionList
shouldDelayFocus
textInputLabel={translate('yearPickerPage.selectYear')}
textInputValue={searchText}
textInputMaxLength={4}
Expand Down
51 changes: 0 additions & 51 deletions src/components/SelectionList/BaseListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ import Icon from '@components/Icon';
import * as Expensicons from '@components/Icon/Expensicons';
import OfflineWithFeedback from '@components/OfflineWithFeedback';
import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
import SelectCircle from '@components/SelectCircle';
import useHover from '@hooks/useHover';
import useStyleUtils from '@hooks/useStyleUtils';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import CONST from '@src/CONST';
Expand All @@ -17,15 +15,12 @@ function BaseListItem<TItem extends ListItem>({
pressableStyle,
wrapperStyle,
containerStyle,
selectMultipleStyle,
isDisabled = false,
shouldPreventDefaultFocusOnSelectRow = false,
canSelectMultiple = false,
onSelectRow,
onCheckboxPress,
onDismissError = () => {},
rightHandSideComponent,
checkmarkPosition = CONST.DIRECTION.LEFT,
keyForList,
errors,
pendingAction,
Expand All @@ -34,7 +29,6 @@ function BaseListItem<TItem extends ListItem>({
}: BaseListItemProps<TItem>) {
const theme = useTheme();
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
const {hovered, bind} = useHover();

const rightHandSideComponentRender = () => {
Expand All @@ -49,14 +43,6 @@ function BaseListItem<TItem extends ListItem>({
return rightHandSideComponent;
};

const handleCheckboxPress = () => {
if (onCheckboxPress) {
onCheckboxPress(item);
} else {
onSelectRow(item);
}
};

return (
<OfflineWithFeedback
onClose={() => onDismissError(item)}
Expand All @@ -80,45 +66,8 @@ function BaseListItem<TItem extends ListItem>({
style={pressableStyle}
>
<View style={wrapperStyle}>
{canSelectMultiple && checkmarkPosition === CONST.DIRECTION.LEFT && (
<PressableWithFeedback
accessibilityLabel={item.text ?? ''}
role={CONST.ROLE.BUTTON}
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
disabled={isDisabled || item.isDisabledCheckbox}
onPress={handleCheckboxPress}
style={[styles.cursorUnset, StyleUtils.getCheckboxPressableStyle(), item.isDisabledCheckbox && styles.cursorDisabled, styles.mr3]}
>
<View style={selectMultipleStyle}>
{item.isSelected && (
<Icon
src={Expensicons.Checkmark}
fill={theme.textLight}
height={14}
width={14}
/>
)}
</View>
</PressableWithFeedback>
)}

{typeof children === 'function' ? children(hovered) : children}

{canSelectMultiple && checkmarkPosition === CONST.DIRECTION.RIGHT && (
<PressableWithFeedback
onPress={handleCheckboxPress}
disabled={isDisabled}
role={CONST.ROLE.BUTTON}
accessibilityLabel={item.text ?? ''}
style={[styles.ml2, styles.optionSelectCircle]}
>
<SelectCircle
isChecked={item.isSelected ?? false}
selectCircleStyles={styles.ml0}
/>
</PressableWithFeedback>
)}

{!canSelectMultiple && item.isSelected && !rightHandSideComponent && (
<View
style={[styles.flexRow, styles.alignItemsCenter, styles.ml3]}
Expand Down
2 changes: 0 additions & 2 deletions src/components/SelectionList/BaseSelectionList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ function BaseSelectionList<TItem extends ListItem>(
shouldShowTooltips = true,
shouldUseDynamicMaxToRenderPerBatch = false,
rightHandSideComponent,
checkmarkPosition,
isLoadingNewOptions = false,
onLayout,
customListHeader,
Expand Down Expand Up @@ -332,7 +331,6 @@ function BaseSelectionList<TItem extends ListItem>(
onDismissError={() => onDismissError?.(item)}
shouldPreventDefaultFocusOnSelectRow={shouldPreventDefaultFocusOnSelectRow}
rightHandSideComponent={rightHandSideComponent}
checkmarkPosition={checkmarkPosition}
keyForList={item.keyForList ?? ''}
isMultilineSupported={isRowMultilineSupported}
/>
Expand Down
134 changes: 134 additions & 0 deletions src/components/SelectionList/InviteMemberListItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import Str from 'expensify-common/lib/str';
shubham1206agra marked this conversation as resolved.
Show resolved Hide resolved
import React, {useCallback} from 'react';
import {View} from 'react-native';
import MultipleAvatars from '@components/MultipleAvatars';
import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
import SelectCircle from '@components/SelectCircle';
import SubscriptAvatar from '@components/SubscriptAvatar';
import Text from '@components/Text';
import TextWithTooltip from '@components/TextWithTooltip';
import useLocalize from '@hooks/useLocalize';
import useStyleUtils from '@hooks/useStyleUtils';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import CONST from '@src/CONST';
import BaseListItem from './BaseListItem';
import type {InviteMemberListItemProps} from './types';

function InviteMemberListItem({
item,
isFocused,
showTooltip,
isDisabled,
canSelectMultiple,
onSelectRow,
onCheckboxPress,
onDismissError,
shouldPreventDefaultFocusOnSelectRow,
rightHandSideComponent,
}: InviteMemberListItemProps) {
const styles = useThemeStyles();
const theme = useTheme();
const StyleUtils = useStyleUtils();
const {translate} = useLocalize();

const focusedBackgroundColor = styles.sidebarLinkActive.backgroundColor;
const subscriptAvatarBorderColor = isFocused ? focusedBackgroundColor : theme.sidebar;
const hoveredBackgroundColor = !!styles.sidebarLinkHover && 'backgroundColor' in styles.sidebarLinkHover ? styles.sidebarLinkHover.backgroundColor : theme.sidebar;

const handleCheckboxPress = useCallback(() => {
if (onCheckboxPress) {
onCheckboxPress(item);
} else {
onSelectRow(item);
}
}, [item, onCheckboxPress, onSelectRow]);

return (
<BaseListItem
item={item}
wrapperStyle={[styles.flex1, styles.justifyContentBetween, styles.sidebarLinkInner, styles.userSelectNone, styles.peopleRow, isFocused && styles.sidebarLinkActive]}
isFocused={isFocused}
isDisabled={isDisabled}
showTooltip={showTooltip}
canSelectMultiple={canSelectMultiple}
onSelectRow={onSelectRow}
onDismissError={onDismissError}
shouldPreventDefaultFocusOnSelectRow={shouldPreventDefaultFocusOnSelectRow}
rightHandSideComponent={rightHandSideComponent}
errors={item.errors}
pendingAction={item.pendingAction}
FooterComponent={
item.invitedSecondaryLogin ? (
<Text style={[styles.ml9, styles.ph5, styles.pb3, styles.textLabelSupporting]}>
{translate('workspace.people.invitedBySecondaryLogin', {secondaryLogin: item.invitedSecondaryLogin})}
</Text>
) : undefined
}
keyForList={item.keyForList}
>
{(hovered?: boolean) => (
<>
{!!item.icons &&
(item.shouldShowSubscript ? (
<SubscriptAvatar
mainAvatar={item.icons[0]}
secondaryAvatar={item.icons[1]}
showTooltip={showTooltip}
backgroundColor={hovered && !isFocused ? hoveredBackgroundColor : subscriptAvatarBorderColor}
/>
) : (
<MultipleAvatars
icons={item.icons ?? []}
shouldShowTooltip={showTooltip}
secondAvatarStyle={[
StyleUtils.getBackgroundAndBorderStyle(theme.sidebar),
isFocused ? StyleUtils.getBackgroundAndBorderStyle(focusedBackgroundColor) : undefined,
hovered && !isFocused ? StyleUtils.getBackgroundAndBorderStyle(hoveredBackgroundColor) : undefined,
]}
/>
))}
<View style={[styles.flex1, styles.flexColumn, styles.justifyContentCenter, styles.alignItemsStretch, styles.optionRow]}>
<TextWithTooltip
shouldShowTooltip={showTooltip}
text={Str.removeSMSDomain(item.text ?? '')}
style={[
styles.optionDisplayName,
isFocused ? styles.sidebarLinkActiveText : styles.sidebarLinkText,
item.isBold !== false && styles.sidebarLinkTextBold,
styles.pre,
item.alternateText ? styles.mb1 : null,
]}
/>
{!!item.alternateText && (
<TextWithTooltip
shouldShowTooltip={showTooltip}
text={Str.removeSMSDomain(item.alternateText ?? '')}
style={[styles.textLabelSupporting, styles.lh16, styles.pre]}
/>
)}
</View>
{!!item.rightElement && item.rightElement}
{canSelectMultiple && (
<PressableWithFeedback
onPress={handleCheckboxPress}
disabled={isDisabled}
role={CONST.ROLE.BUTTON}
accessibilityLabel={item.text ?? ''}
style={[styles.ml2, styles.optionSelectCircle]}
>
<SelectCircle
isChecked={item.isSelected ?? false}
selectCircleStyles={styles.ml0}
/>
</PressableWithFeedback>
)}
</>
)}
</BaseListItem>
);
}

InviteMemberListItem.displayName = 'InviteMemberListItem';

export default InviteMemberListItem;
9 changes: 0 additions & 9 deletions src/components/SelectionList/RadioListItem.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React from 'react';
import {View} from 'react-native';
import TextWithTooltip from '@components/TextWithTooltip';
import useStyleUtils from '@hooks/useStyleUtils';
import useThemeStyles from '@hooks/useThemeStyles';
import CONST from '@src/CONST';
import BaseListItem from './BaseListItem';
Expand All @@ -12,17 +11,13 @@ function RadioListItem({
isFocused,
showTooltip,
isDisabled,
canSelectMultiple,
onSelectRow,
onCheckboxPress,
onDismissError,
shouldPreventDefaultFocusOnSelectRow,
rightHandSideComponent,
checkmarkPosition,
isMultilineSupported = false,
}: RadioListItemProps) {
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
const fullTitle = isMultilineSupported ? item.text?.trimStart() : item.text;
const indentsLength = (item.text?.length ?? 0) - (fullTitle?.length ?? 0);
const paddingLeft = Math.floor(indentsLength / CONST.INDENTS.length) * styles.ml3.marginLeft;
Expand All @@ -31,17 +26,13 @@ function RadioListItem({
<BaseListItem
item={item}
wrapperStyle={[styles.flex1, styles.justifyContentBetween, styles.sidebarLinkInner, styles.userSelectNone, styles.optionRow, isFocused && styles.sidebarLinkActive]}
selectMultipleStyle={[StyleUtils.getCheckboxContainerStyle(20), StyleUtils.getMultiselectListStyles(!!item.isSelected, !!item.isDisabled)]}
isFocused={isFocused}
isDisabled={isDisabled}
showTooltip={showTooltip}
canSelectMultiple={canSelectMultiple}
onSelectRow={onSelectRow}
onCheckboxPress={onCheckboxPress}
onDismissError={onDismissError}
shouldPreventDefaultFocusOnSelectRow={shouldPreventDefaultFocusOnSelectRow}
rightHandSideComponent={rightHandSideComponent}
checkmarkPosition={checkmarkPosition}
keyForList={item.keyForList}
>
<>
Expand Down
39 changes: 34 additions & 5 deletions src/components/SelectionList/TableListItem.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import React from 'react';
import React, {useCallback} from 'react';
import {View} from 'react-native';
import Icon from '@components/Icon';
import * as Expensicons from '@components/Icon/Expensicons';
import MultipleAvatars from '@components/MultipleAvatars';
import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
import TextWithTooltip from '@components/TextWithTooltip';
import useStyleUtils from '@hooks/useStyleUtils';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import CONST from '@src/CONST';
import BaseListItem from './BaseListItem';
import type {TableListItemProps} from './types';

Expand All @@ -19,7 +23,6 @@ function TableListItem({
onDismissError,
shouldPreventDefaultFocusOnSelectRow,
rightHandSideComponent,
checkmarkPosition,
}: TableListItemProps) {
const styles = useThemeStyles();
const theme = useTheme();
Expand All @@ -28,29 +31,55 @@ function TableListItem({
const focusedBackgroundColor = styles.sidebarLinkActive.backgroundColor;
const hoveredBackgroundColor = styles.sidebarLinkHover?.backgroundColor ? styles.sidebarLinkHover.backgroundColor : theme.sidebar;

const handleCheckboxPress = useCallback(() => {
if (onCheckboxPress) {
onCheckboxPress(item);
} else {
onSelectRow(item);
}
}, [item, onCheckboxPress, onSelectRow]);

return (
<BaseListItem
item={item}
pressableStyle={[[styles.selectionListPressableItemWrapper, item.isSelected && styles.activeComponentBG, isFocused && styles.sidebarLinkActive]]}
wrapperStyle={[styles.flexRow, styles.flex1, styles.justifyContentBetween, styles.userSelectNone, styles.alignItemsCenter]}
containerStyle={styles.mb3}
selectMultipleStyle={[StyleUtils.getCheckboxContainerStyle(20), StyleUtils.getMultiselectListStyles(!!item.isSelected, !!item.isDisabled)]}
isFocused={isFocused}
isDisabled={isDisabled}
showTooltip={showTooltip}
canSelectMultiple={canSelectMultiple}
onSelectRow={onSelectRow}
onCheckboxPress={onCheckboxPress}
onDismissError={onDismissError}
shouldPreventDefaultFocusOnSelectRow={shouldPreventDefaultFocusOnSelectRow}
rightHandSideComponent={rightHandSideComponent}
checkmarkPosition={checkmarkPosition}
errors={item.errors}
pendingAction={item.pendingAction}
keyForList={item.keyForList}
>
{(hovered) => (
<>
{canSelectMultiple && (
<PressableWithFeedback
shubham1206agra marked this conversation as resolved.
Show resolved Hide resolved
accessibilityLabel={item.text ?? ''}
role={CONST.ROLE.BUTTON}
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
disabled={isDisabled || item.isDisabledCheckbox}
onPress={handleCheckboxPress}
style={[styles.cursorUnset, StyleUtils.getCheckboxPressableStyle(), item.isDisabledCheckbox && styles.cursorDisabled, styles.mr3]}
>
<View style={[StyleUtils.getCheckboxContainerStyle(20), StyleUtils.getMultiselectListStyles(!!item.isSelected, !!item.isDisabled)]}>
{item.isSelected && (
<Icon
src={Expensicons.Checkmark}
fill={theme.textLight}
height={14}
width={14}
/>
)}
</View>
</PressableWithFeedback>
)}
{!!item.icons && (
<MultipleAvatars
icons={item.icons ?? []}
Expand Down
Loading
Loading