Skip to content

Commit 824a708

Browse files
committed
feat: add component avatar
1 parent 1c3227c commit 824a708

File tree

11 files changed

+267
-1
lines changed

11 files changed

+267
-1
lines changed

packages/ui-variants/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ export * from './types';
55
export * from './variants/accordion';
66
export * from './variants/alert';
77
export * from './variants/alert-dialog';
8+
export * from './variants/avatar';
89
export * from './variants/badge';
910
export * from './variants/button';
1011
export * from './variants/button-group';
1112
export * from './variants/card';
1213
export * from './variants/divider';
1314
export * from './variants/scroll-area';
14-
1515
export * from './variants/tabs';

packages/ui/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"@radix-ui/react-accordion": "^1.2.11",
1515
"@radix-ui/react-alert-dialog": "^1.1.14",
1616
"@radix-ui/react-aspect-ratio": "^1.1.7",
17+
"@radix-ui/react-avatar": "^1.1.10",
1718
"@radix-ui/react-compose-refs": "1.1.2",
1819
"@radix-ui/react-scroll-area": "^1.2.9",
1920
"@radix-ui/react-separator": "^1.1.7",
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export { default as Avatar } from './source/Avatar';
2+
export { default as AvatarFallback } from './source/AvatarFallback';
3+
export { default as AvatarImage } from './source/AvatarImage';
4+
export { default as AvatarRoot } from './source/AvatarRoot';
5+
6+
export * from './types';
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { Image } from '@radix-ui/react-avatar';
2+
import type { ElementRef } from 'react';
3+
import { forwardRef } from 'react';
4+
5+
import type { AvatarProps } from '../types';
6+
7+
import AvatarFallback from './AvatarFallback';
8+
import AvatarImage from './AvatarImage';
9+
import AvatarRoot from './AvatarRoot';
10+
11+
const Avatar = forwardRef<ElementRef<typeof Image>, AvatarProps>((props, ref) => {
12+
const { className, classNames, delayMs, fallback, size, ...rest } = props;
13+
14+
return (
15+
<AvatarRoot
16+
className={classNames?.root}
17+
size={size}
18+
>
19+
<AvatarImage
20+
className={className || classNames?.image}
21+
ref={ref}
22+
{...rest}
23+
/>
24+
25+
<AvatarFallback
26+
className={classNames?.fallback}
27+
delayMs={delayMs}
28+
>
29+
{fallback}
30+
</AvatarFallback>
31+
</AvatarRoot>
32+
);
33+
});
34+
35+
Avatar.displayName = Image.displayName;
36+
37+
export default Avatar;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { Fallback } from '@radix-ui/react-avatar';
2+
import { avatarVariants, cn } from '@soybean-react-ui/variants';
3+
import type { ElementRef } from 'react';
4+
import { forwardRef } from 'react';
5+
6+
import type { AvatarFallbackProps } from '../types';
7+
8+
const AvatarFallback = forwardRef<ElementRef<typeof Fallback>, AvatarFallbackProps>((props, ref) => {
9+
const { className, ...rest } = props;
10+
11+
const { fallback } = avatarVariants();
12+
13+
const mergedCls = cn(fallback(), className);
14+
15+
return (
16+
<Fallback
17+
className={mergedCls}
18+
ref={ref}
19+
{...rest}
20+
/>
21+
);
22+
});
23+
24+
AvatarFallback.displayName = Fallback.displayName;
25+
26+
export default AvatarFallback;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { Image } from '@radix-ui/react-avatar';
2+
import { avatarVariants, cn } from '@soybean-react-ui/variants';
3+
import type { ElementRef } from 'react';
4+
import { forwardRef } from 'react';
5+
6+
import type { AvatarImageProps } from '../types';
7+
8+
const AvatarImage = forwardRef<ElementRef<typeof Image>, AvatarImageProps>((props, ref) => {
9+
const { className, ...rest } = props;
10+
11+
const { image } = avatarVariants();
12+
13+
const mergedCls = cn(image(), className);
14+
15+
return (
16+
<Image
17+
className={mergedCls}
18+
ref={ref}
19+
{...rest}
20+
/>
21+
);
22+
});
23+
24+
AvatarImage.displayName = Image.displayName;
25+
26+
export default AvatarImage;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { Root } from '@radix-ui/react-avatar';
2+
import { avatarVariants, cn } from '@soybean-react-ui/variants';
3+
import type { ElementRef } from 'react';
4+
import { forwardRef } from 'react';
5+
6+
import type { AvatarRootProps } from '../types';
7+
8+
const AvatarRoot = forwardRef<ElementRef<typeof Root>, AvatarRootProps>((props, ref) => {
9+
const { className, size, ...rest } = props;
10+
11+
const { root } = avatarVariants({ size });
12+
13+
const mergedCls = cn(root(), className);
14+
15+
return (
16+
<Root
17+
className={mergedCls}
18+
ref={ref}
19+
{...rest}
20+
/>
21+
);
22+
});
23+
24+
AvatarRoot.displayName = Root.displayName;
25+
26+
export default AvatarRoot;
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import type {
2+
AvatarFallbackProps as _AvatarFallbackProps,
3+
AvatarImageProps as _AvatarImageProps,
4+
AvatarProps as _AvatarRootProps
5+
} from '@radix-ui/react-avatar';
6+
import type { AvatarSlots } from '@soybean-react-ui/variants';
7+
8+
import type { BaseNodeProps, ClassValue } from '../../types/other';
9+
10+
export type AvatarUi = Partial<Record<AvatarSlots, ClassValue>>;
11+
12+
export type AvatarRootProps = BaseNodeProps<_AvatarRootProps>;
13+
14+
export type AvatarFallbackProps = BaseNodeProps<_AvatarFallbackProps>;
15+
16+
export type AvatarImageProps = BaseNodeProps<_AvatarImageProps>;
17+
18+
export interface AvatarProps extends AvatarImageProps, Pick<AvatarFallbackProps, 'delayMs'> {
19+
classNames?: AvatarUi;
20+
fallback?: React.ReactNode;
21+
}

packages/ui/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ export * from './components/alert-dialog';
66

77
export * from './components/aspect-ratio';
88

9+
export * from './components/avatar';
10+
911
export * from './components/badge';
1012

1113
export * from './components/button';
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import Image from 'next/image';
2+
import type { ThemeSize } from 'soybean-react-ui';
3+
import { Avatar, Card } from 'soybean-react-ui';
4+
5+
const soybeanUiRsc = 'https://soybean-ui.com/logo.svg';
6+
7+
const soybeanSrc = 'https://soybeanjs-1300612522.cos.ap-guangzhou.myqcloud.com/uPic/logo.png';
8+
9+
const sizes: ThemeSize[] = ['xs', 'sm', 'md', 'lg', 'xl', '2xl'];
10+
11+
const AvatarPage = () => {
12+
return (
13+
<div className="flex flex-col gap-4">
14+
<Card
15+
split
16+
title="Default"
17+
>
18+
<div className="flex gap-[12px]">
19+
<Avatar
20+
alt="Soybean UI"
21+
fallback="CN"
22+
src={soybeanUiRsc}
23+
/>
24+
25+
<Avatar
26+
alt="Soybean UI"
27+
classNames={{ fallback: 'bg-foreground ' }}
28+
src={soybeanUiRsc}
29+
fallback={
30+
<Image
31+
alt="Vercel logomark"
32+
className="dark:invert"
33+
height={20}
34+
src="/vercel.svg"
35+
width={20}
36+
/>
37+
}
38+
/>
39+
</div>
40+
</Card>
41+
42+
<Card
43+
split
44+
title="Sizes"
45+
>
46+
<div className="flex flex-wrap gap-[12px]">
47+
{sizes.map(size => (
48+
<div
49+
className="flex-c-center"
50+
key={size}
51+
>
52+
<Avatar
53+
alt="Soybean UI"
54+
fallback="SOY"
55+
size={size}
56+
src={soybeanSrc}
57+
/>
58+
<p>{size}</p>
59+
</div>
60+
))}
61+
</div>
62+
</Card>
63+
</div>
64+
);
65+
};
66+
67+
export default AvatarPage;

0 commit comments

Comments
 (0)