import React, { useCallback, useMemo } from 'react'; import { StyleSheet, View } from 'react-native'; import { UserResponse } from 'stream-chat'; import { Avatar, AvatarProps } from './Avatar'; import { iconSizes } from './constants'; import { UserAvatar, UserAvatarProps } from './UserAvatar'; import { useTheme } from '../../../contexts/themeContext/ThemeContext'; import { PeopleIcon } from '../../../icons/users'; import { primitives } from '../../../theme'; import { BadgeCount, BadgeCountProps, OnlineIndicator, OnlineIndicatorProps } from '../Badge'; export type AvatarGroupProps = { /** * The size of the avatar group. */ size: 'lg' | 'xl' | '2xl'; /** * The items to display in the avatar group. */ items: React.ReactNode[]; }; // Sizes accounts for the border width as well const sizes = { '2xl': { width: 64, height: 64, }, xl: { width: 48, height: 48, }, lg: { width: 44, height: 44, }, }; const buildForTwo = (items: React.ReactNode[]) => { return ( <> {items[0]} {items[1]} ); }; const buildForThree = (items: React.ReactNode[]) => { return ( <> {items[0]} {items[1]} {items[2]} ); }; const buildForFour = (items: React.ReactNode[]) => { return ( <> {items[0]} {items[1]} {items[2]} {items[3]} ); }; const avatarSize: Record = { '2xl': 'lg', xl: 'md', lg: 'sm', }; const badgeCountSize: Record = { '2xl': 'lg', xl: 'md', lg: 'sm', }; export const AvatarGroup = (props: AvatarGroupProps) => { const { size, items = [] } = props; const { theme: { semantics }, } = useTheme(); const avatarGroupStyles = useUserAvatarGroupStyles(); const buildForOne = useCallback( (item: React.ReactNode) => { return buildForTwo([ item, } size={avatarSize[size]} />, ]); }, [avatarGroupStyles.userAvatarWrapper, semantics, size], ); const buildForMore = useCallback( (items: React.ReactNode[]) => { const remainingItems = items.length - 2; return ( <> {items[0]} {items[1]} ); }, [size], ); const renderItems = useMemo(() => { const length = items.length; if (length === 1) { return buildForOne(items[0]); } if (length === 2) { return buildForTwo(items); } if (length === 3) { return buildForThree(items); } if (length === 4) { return buildForFour(items); } return buildForMore(items); }, [buildForMore, buildForOne, items]); return ( {renderItems} ); }; export type UserAvatarGroupProps = Pick & { /** * The users to display in the avatar group. */ users: UserResponse[]; /** * Whether to show the online indicator. */ showOnlineIndicator?: boolean; }; const userAvatarSize: Record = { '2xl': 'lg', xl: 'md', lg: 'sm', }; const onlineIndicatorSize: Record = { '2xl': 'xl', xl: 'xl', lg: 'lg', }; export const UserAvatarGroup = ({ users, showOnlineIndicator = true, size, }: UserAvatarGroupProps) => { const styles = useUserAvatarGroupStyles(); return ( ( ))} /> {showOnlineIndicator ? ( ) : null} ); }; const useUserAvatarGroupStyles = () => { const { theme: { semantics }, } = useTheme(); return useMemo( () => StyleSheet.create({ userAvatarWrapper: { borderWidth: 2, borderColor: semantics.borderCoreInverse, borderRadius: primitives.radiusMax, }, onlineIndicatorWrapper: { position: 'absolute', right: 0, top: 0, }, }), [semantics], ); }; const styles = StyleSheet.create({ container: {}, topStart: { position: 'absolute', top: 0, left: 0, }, bottomEnd: { position: 'absolute', bottom: 0, right: 0, }, topEnd: { position: 'absolute', top: 0, right: 0, }, bottomStart: { position: 'absolute', bottom: 0, left: 0, }, topCenter: { alignItems: 'center', }, bottomCenter: { position: 'absolute', bottom: 0, alignSelf: 'center', }, });