Avatar
An image that represents a person on your platform.
Installation
1
Run the following command:
npx nwui-cli@latest add avatar
🚀
1
Copy/paste the following code to the specified file path:
~/components/nativewindui/Avatar.tsx
import * as React from 'react';
import {
ImageErrorEventData,
ImageLoadEventData,
NativeSyntheticEvent,
Image as RNImage,
View,
} from 'react-native';
import { cn } from '~/lib/cn';
interface AvatarRootProps {
alt: string;
}
interface AvatarImageProps {
children?: React.ReactNode;
onLoadingStatusChange?: (status: 'error' | 'loaded') => void;
}
type AvatarState = 'loading' | 'error' | 'loaded';
interface IRootContext extends AvatarRootProps {
status: AvatarState;
setStatus: (status: AvatarState) => void;
}
const RootContext = React.createContext<IRootContext | null>(null);
const Avatar = React.forwardRef<
React.ElementRef<typeof View>,
React.ComponentPropsWithoutRef<typeof View> & AvatarRootProps
>(({ alt, className, ...viewProps }, ref) => {
const [status, setStatus] = React.useState<AvatarState>('error');
return (
<RootContext.Provider value={{ alt, status, setStatus }}>
<View
ref={ref}
className={cn('relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full', className)}
{...viewProps}
/>
</RootContext.Provider>
);
});
Avatar.displayName = 'Avatar';
function useRootContext() {
const context = React.useContext(RootContext);
if (!context) {
throw new Error('Avatar compound components cannot be rendered outside the Avatar component');
}
return context;
}
const AvatarImage = React.forwardRef<
React.ElementRef<typeof RNImage>,
Omit<React.ComponentPropsWithoutRef<typeof RNImage>, 'alt'> & AvatarImageProps
>(
(
{ onLoad: onLoadProps, onError: onErrorProps, onLoadingStatusChange, className, ...props },
ref
) => {
const { alt, setStatus, status } = useRootContext();
React.useLayoutEffect(() => {
setStatus('loading');
}, []);
const onLoad = React.useCallback(
(e: NativeSyntheticEvent<ImageLoadEventData>) => {
setStatus('loaded');
onLoadingStatusChange?.('loaded');
onLoadProps?.(e);
},
[onLoadProps]
);
const onError = React.useCallback(
(e: NativeSyntheticEvent<ImageErrorEventData>) => {
setStatus('error');
onLoadingStatusChange?.('error');
onErrorProps?.(e);
},
[onErrorProps]
);
if (status === 'error') {
return null;
}
return (
<RNImage
ref={ref}
alt={alt}
onLoad={onLoad}
onError={onError}
className={cn('aspect-square h-full w-full', className)}
{...props}
/>
);
});
AvatarImage.displayName = 'AvatarImage';
const AvatarFallback = React.forwardRef<
React.ElementRef<typeof View>,
React.ComponentPropsWithoutRef<typeof View>
>(({ className, ...props }, ref) => {
const { alt, status } = useRootContext();
if (status !== 'error') {
return null;
}
return (
<View
ref={ref}
role="img"
aria-label={alt}
className={cn(
'flex h-full w-full items-center justify-center rounded-full bg-muted',
className
)}
{...props}
/>
);
});
AvatarFallback.displayName = 'AvatarFallback';
export { Avatar, AvatarFallback, AvatarImage };
🚢
Usage
index.tsx
import { Text, View } from 'react-native';
import { Avatar, AvatarFallback, AvatarImage } from '~/components/nativewindui/Avatar';
const TWITTER_AVATAR_URI =
'https://pbs.twimg.com/profile_images/1782428433898708992/1voyv4_A_400x400.jpg';
function AvatarExample() {
return (
<View className="items-center">
<Avatar alt="NativeWindUI Avatar">
<AvatarImage source={{ uri: TWITTER_AVATAR_URI }} />
<AvatarFallback>
<Text className="text-foreground">NUI</Text>
</AvatarFallback>
</Avatar>
</View>
);
}
© Ronin Technologies LLC 2024