Avatar
사용자의 프로필 이미지를 표시하는 컴포넌트입니다.
import "./styles";
import { Avatar, AvatarBadge } from "@/components/ui/avatar";
import { IdentityPlaceholder } from "@/components/ui/identity-placeholder";
export default function AvatarPreview() {
return (
<view className="avatar-row">
<Avatar
size="80"
badgeMask="circle"
src="https://avatars.githubusercontent.com/u/54893898?v=4"
fallback={<IdentityPlaceholder />}
>
<AvatarBadge accessibility-label="온라인">
<view className="avatar-online" />
</AvatarBadge>
</Avatar>
<Avatar size="80" fallback={<IdentityPlaceholder />} />
</view>
);
}
npx @seed-design/cli@latest add ui:avatar
pnpm dlx @seed-design/cli@latest add ui:avatar
yarn dlx @seed-design/cli@latest add ui:avatar
bun x @seed-design/cli@latest add ui:avatar
의존성 설치
npm install @seed-design/lynx-react
yarn add @seed-design/lynx-react
pnpm add @seed-design/lynx-react
bun add @seed-design/lynx-react
아래 코드를 복사 후 붙여넣고 사용하세요
/**
* @file ui:avatar
* @requires @seed-design/lynx-react@^1.0.0
* @requires @seed-design/lynx-css@^1.0.0
**/
import * as React from "@lynx-js/react";
import { Avatar as SeedAvatar } from "@seed-design/lynx-react";
export interface AvatarProps extends SeedAvatar.RootProps {
src?: string;
alt?: string;
fallback?: React.ReactNode;
/** Native image events and accessibility attributes. */
imageProps?: Omit<SeedAvatar.ImageProps, "src" | "alt">;
}
/** @see https://seed-design.io/lynx/components/avatar */
export const Avatar = React.forwardRef<unknown, AvatarProps>(
({ src, alt, fallback, imageProps, children, ...otherProps }, ref) => (
<SeedAvatar.Root {...(ref ? { ref } : {})} {...otherProps}>
<SeedAvatar.Fallback>
{typeof fallback === "string" || typeof fallback === "number" ? (
<text>{fallback}</text>
) : (
fallback
)}
</SeedAvatar.Fallback>
<SeedAvatar.Image src={src} alt={alt} {...imageProps} />
{children}
</SeedAvatar.Root>
),
);
Avatar.displayName = "Avatar";
export interface AvatarBadgeProps extends SeedAvatar.BadgeProps {}
export const AvatarBadge = SeedAvatar.Badge;
export interface AvatarStackProps extends SeedAvatar.StackProps {}
export const AvatarStack = SeedAvatar.Stack;
/**
* This file is a snippet from SEED Design, helping you get started quickly with @seed-design/* packages.
* You can extend this snippet however you want.
*/
import { Avatar } from "@/components/ui/avatar";
import { IdentityPlaceholder } from "@/components/ui/identity-placeholder";
<Avatar src="https://avatars.githubusercontent.com/u/54893898?v=4" alt="사용자 프로필" fallback={<IdentityPlaceholder />} />
이미지가 로딩 중이거나 실패한 동안 fallback을 표시합니다. src가 바뀌면 새 요청을 시작하며, 이전 요청의 이벤트는 상태에 반영하지 않습니다.
onLoadingStatusChange로 로딩 상태를 관찰할 수 있습니다. native 이미지 이벤트와 접근성 속성은 imageProps에 전달합니다.
<Avatar
src="https://avatars.githubusercontent.com/u/54893898?v=4"
alt="사용자 프로필"
imageProps={{
binderror: () => { "background only"; console.log("프로필 이미지 로딩 실패"); },
}}
/>
src?string | undefined
alt?string | undefined
fallback?React.ReactNode
onLoadingStatusChange?((status: ImageLoadingStatus) => void) | undefined
고유 prop이 없습니다. native view 속성과 children, className, style을 받습니다.
import "./styles";
import { Avatar } from "@/components/ui/avatar";
export default function AvatarSize() {
return (
<view className="avatar-row">
{(["20", "24", "36", "42", "48", "56", "64", "80", "96", "108"] as const).map((size) => (
<Avatar
key={size}
size={size}
src="https://avatars.githubusercontent.com/u/54893898?v=4"
fallback="L"
/>
))}
</view>
);
}
badgeMask는 이미지와 fallback에서 배지 주변을 "circle", "flower", "shield" 모양으로 잘라냅니다. 기본값인 "none"은 아바타를 자르지 않습니다. size="20"에서는 배지와 마스크를 모두 표시하지 않습니다.
AvatarBadge에는 선택한 마스크 모양에 맞는 에셋을 넣습니다. 다른 모양의 콘텐츠에는 badgeMask="none"을 사용하고 필요한 테두리를 직접 지정하세요.
import { Avatar, AvatarBadge } from "@/components/ui/avatar";
<Avatar size="64" src={profile.imageUrl} alt={profile.name} badgeMask="shield">
<AvatarBadge>
<image
src={shieldBadgeSrc}
accessibility-label="인증된 프로필"
mode="aspectFit"
style={{ width: "100%", height: "100%" }}
/>
</AvatarBadge>
</Avatar>
직접 만든 배지는 badgeMask="none"과 children으로 구성합니다.
<Avatar size="64" src={profile.imageUrl} alt={profile.name} badgeMask="none">
<AvatarBadge>
<view style={{ width: "100%", height: "100%", display: "flex", alignItems: "center", justifyContent: "center", backgroundColor: "#20242B", borderRadius: "6px" }}>
<text style={{ color: "#FFFFFF", fontSize: "12px" }}>+3</text>
</view>
</AvatarBadge>
</Avatar>
import "./styles";
import shield_blue_checkmark from "./shield_blue_checkmark.webp";
import flower_green_checkmark from "./flower_green_checkmark.webp";
import { Avatar, AvatarBadge } from "@/components/ui/avatar";
import { IdentityPlaceholder } from "@/components/ui/identity-placeholder";
export default function AvatarBadgeExample() {
return (
<view className="avatar-row">
<Avatar
size="64"
badgeMask="circle"
src="https://avatars.githubusercontent.com/u/54893898?v=4"
fallback={<IdentityPlaceholder />}
>
<AvatarBadge accessibility-label="온라인">
<view className="avatar-online" />
</AvatarBadge>
</Avatar>
<Avatar
size="64"
badgeMask="flower"
src="https://avatars.githubusercontent.com/u/54893898?v=4"
fallback={<IdentityPlaceholder />}
>
<AvatarBadge>
<image
className="avatar-badge-image"
src={flower_green_checkmark}
accessibility-label="인증된 프로필"
/>
</AvatarBadge>
</Avatar>
<Avatar
size="64"
badgeMask="shield"
src="https://avatars.githubusercontent.com/u/54893898?v=4"
fallback={<IdentityPlaceholder />}
>
<AvatarBadge>
<image
className="avatar-badge-image"
src={shield_blue_checkmark}
accessibility-label="보호된 프로필"
/>
</AvatarBadge>
</Avatar>
</view>
);
}
AvatarStack은 자식 Avatar에 size를 전달합니다. 개별 Avatar에 지정한 size가 우선합니다.
import { Avatar, AvatarStack } from "@/components/ui/avatar";
<AvatarStack size="48">
<Avatar src={first.imageUrl} alt={first.name} />
<Avatar src={second.imageUrl} alt={second.name} size="36" />
<Avatar fallback="김" />
</AvatarStack>
import "./styles";
import { Avatar, AvatarStack } from "@/components/ui/avatar";
import { IdentityPlaceholder } from "@/components/ui/identity-placeholder";
export default function AvatarStackExample() {
return (
<AvatarStack size="64">
{(["first", "second", "third", "fourth"] as const).map((id) => (
<Avatar
key={id}
src="https://avatars.githubusercontent.com/u/54893898?v=4"
fallback={<IdentityPlaceholder />}
/>
))}
</AvatarStack>
);
}
fallback에는 이미지가 로드되지 않았을 때 표시할 요소를 지정합니다. 문자열과 숫자도 사용할 수 있으며, 주로 IdentityPlaceholder를 사용합니다.
로딩에 성공하면 fallback을 언마운트합니다. 다시 표시할 때 유지해야 하는 상태는 부모에서 관리하세요.
import "./styles";
import { Avatar } from "@/components/ui/avatar";
import { IdentityPlaceholder } from "@/components/ui/identity-placeholder";
export default function AvatarFallbackExample() {
return (
<view className="avatar-row">
<Avatar size="80" fallback={<IdentityPlaceholder identity="person" />} />
<Avatar size="80" fallback={<IdentityPlaceholder identity="business" />} />
</view>
);
}
- DOM
<img> 대신 native <image mode="aspectFill">을 사용합니다. alt는 accessibility-label로 전달합니다.
onLoad와 onError 대신 imageProps.bindload와 imageProps.binderror를 사용합니다.
- Stack에서 영역 밖 콘텐츠를 함께 사용하면 React와 겹침 결과가 다를 수 있습니다.
asChild, srcSet, DOM 이벤트와 속성은 지원하지 않습니다.