forked from mantinedev/mantine
/
Avatar.tsx
108 lines (90 loc) · 2.8 KB
/
Avatar.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import React, { useEffect, useState, forwardRef } from 'react';
import {
DefaultProps,
MantineNumberSize,
MantineColor,
Selectors,
useComponentDefaultProps,
MantineGradient,
} from '@mantine/styles';
import { createPolymorphicComponent } from '@mantine/utils';
import { Box } from '../Box';
import { AvatarPlaceholderIcon } from './AvatarPlaceholderIcon';
import { AvatarGroup } from './AvatarGroup/AvatarGroup';
import { useAvatarGroupContext } from './AvatarGroup/AvatarGroup.context';
import useStyles, { AvatarStylesParams, AvatarVariant } from './Avatar.styles';
export type AvatarStylesNames = Selectors<typeof useStyles>;
export interface AvatarProps extends DefaultProps<AvatarStylesNames, AvatarStylesParams> {
/** Image url */
src?: string | null;
/** Image alt text or title for placeholder variant */
alt?: string;
/** Avatar width and height */
size?: MantineNumberSize;
/** Value from theme.radius or number to set border-radius in px */
radius?: MantineNumberSize;
/** Color from theme.colors used for letter and icon placeholders */
color?: MantineColor;
/** Controls appearance */
variant?: AvatarVariant;
/** Controls gradient settings in gradient variant only */
gradient?: MantineGradient;
/** img element attributes */
imageProps?: Record<string, any>;
/** Custom placeholder */
children?: React.ReactNode;
}
const defaultProps: Partial<AvatarProps> = {
size: 'md',
color: 'gray',
variant: 'light',
};
export const _Avatar = forwardRef<HTMLDivElement, AvatarProps>((props, ref) => {
const {
className,
size,
src,
alt,
radius,
children,
color,
variant,
gradient,
classNames,
styles,
imageProps,
unstyled,
...others
} = useComponentDefaultProps('Avatar', defaultProps, props);
const ctx = useAvatarGroupContext();
const [error, setError] = useState(!src);
const { classes, cx } = useStyles(
{ color, radius, size, withinGroup: ctx.withinGroup, spacing: ctx.spacing, variant, gradient },
{ classNames, styles, unstyled, name: 'Avatar' }
);
useEffect(() => {
!src ? setError(true) : setError(false);
}, [src]);
return (
<Box component="div" className={cx(classes.root, className)} ref={ref} {...others}>
{error ? (
<div className={classes.placeholder} title={alt}>
{children || <AvatarPlaceholderIcon className={classes.placeholderIcon} />}
</div>
) : (
<img
{...imageProps}
className={classes.image}
src={src}
alt={alt}
onError={() => setError(true)}
/>
)}
</Box>
);
}) as any;
_Avatar.displayName = '@mantine/core/Avatar';
_Avatar.Group = AvatarGroup;
export const Avatar = createPolymorphicComponent<'div', AvatarProps, { Group: typeof AvatarGroup }>(
_Avatar
);