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 @@ -16,15 +14,12 @@ function BaseListItem<TItem extends ListItem>({
item,
pressableStyle,
wrapperStyle,
selectMultipleStyle,
isDisabled = false,
shouldPreventDefaultFocusOnSelectRow = false,
canSelectMultiple = false,
onSelectRow,
onCheckboxPress,
onDismissError = () => {},
rightHandSideComponent,
checkmarkPosition = CONST.DIRECTION.LEFT,
keyForList,
errors,
pendingAction,
Expand All @@ -33,7 +28,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 @@ -48,14 +42,6 @@ function BaseListItem<TItem extends ListItem>({
return rightHandSideComponent;
};

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

return (
<OfflineWithFeedback
onClose={() => onDismissError(item)}
Expand All @@ -78,45 +64,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]}
>
<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
41 changes: 36 additions & 5 deletions src/components/SelectionList/RadioListItem.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
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 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 {RadioListItemProps} from './types';

Expand All @@ -17,30 +22,56 @@ function RadioListItem({
onDismissError,
shouldPreventDefaultFocusOnSelectRow,
rightHandSideComponent,
checkmarkPosition,
isMultilineSupported = false,
}: RadioListItemProps) {
const styles = useThemeStyles();
const theme = useTheme();
const StyleUtils = useStyleUtils();

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.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}
>
<>
{canSelectMultiple && (
<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]}
>
<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>
)}
<View style={[styles.flex1, styles.alignItemsStart]}>
mountiny marked this conversation as resolved.
Show resolved Hide resolved
<TextWithTooltip
shouldShowTooltip={showTooltip}
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,28 +31,54 @@ 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]}
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]}
>
<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
55 changes: 50 additions & 5 deletions src/components/SelectionList/UserListItem.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import Str from 'expensify-common/lib/str';
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 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 {UserListItemProps} from './types';

Expand All @@ -23,7 +28,7 @@ function UserListItem({
onDismissError,
shouldPreventDefaultFocusOnSelectRow,
rightHandSideComponent,
checkmarkPosition,
checkmarkPosition = CONST.DIRECTION.LEFT,
}: UserListItemProps) {
const styles = useThemeStyles();
const theme = useTheme();
Expand All @@ -34,21 +39,26 @@ function UserListItem({
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]}
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}
FooterComponent={
Expand All @@ -62,6 +72,27 @@ function UserListItem({
>
{(hovered?: boolean) => (
<>
{canSelectMultiple && checkmarkPosition === CONST.DIRECTION.LEFT && (
shubham1206agra marked this conversation as resolved.
Show resolved Hide resolved
<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]}
>
<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 &&
(item.shouldShowSubscript ? (
<SubscriptAvatar
Expand Down Expand Up @@ -102,6 +133,20 @@ function UserListItem({
)}
</View>
{!!item.rightElement && item.rightElement}
{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>
)}
</>
)}
</BaseListItem>
Expand Down
20 changes: 0 additions & 20 deletions src/components/SelectionList/index.ios.tsx

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ function SelectionList<TItem extends ListItem>(props: BaseSelectionListProps<TIt
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
ref={ref}
shouldDelayFocus
onScrollBeginDrag={() => Keyboard.dismiss()}
/>
);
Expand Down
Loading
Loading