Use source loader for email sprite icons
[ProtonMail-WebClient.git] / packages / docs-shared / components / UserAvatar.tsx
blob88420db1cade26cb30689f641f6b33de911a7335
1 import type { ForwardedRef, ComponentPropsWithoutRef } from 'react'
2 import { useMemo, forwardRef } from 'react'
3 import clsx from '@proton/utils/clsx'
4 import tinycolor from 'tinycolor2'
5 import { getAccentColorForUsername } from './getAccentColorForUsername'
7 function parseHueFromHSLstring(hsl: string): number | undefined {
8   const NumberRegex = /(\d+)/
9   const numberMatch = hsl.match(NumberRegex)?.[0]
10   return numberMatch ? parseInt(numberMatch) : undefined
13 /** A number between 0 to 360 */
14 type HueValue = number
16 const UserAvatarHueCache = new Map<string, number>()
18 interface UserAvatarProps extends Omit<ComponentPropsWithoutRef<'div'>, 'color'> {
19   name: string
20   className?: string
21   color?: { hue: HueValue } | { hsl: string }
24 export const UserAvatar = forwardRef(function UserAvatar(
25   { name, className, color, ...rest }: UserAvatarProps,
26   ref: ForwardedRef<HTMLDivElement>,
27 ) {
28   if (!name) {
29     throw new Error('UserAvatar requires a name prop')
30   }
32   const hue = useMemo(() => {
33     if (color) {
34       if ('hsl' in color) {
35         if (color.hsl) {
36           const parsed = parseHueFromHSLstring(color.hsl)
37           if (parsed && !isNaN(parsed)) {
38             return parsed
39           }
40         }
41       } else if (!isNaN(color.hue)) {
42         return color.hue
43       }
44     }
46     const cachedHue = UserAvatarHueCache.get(name)
47     if (cachedHue) {
48       return cachedHue
49     }
51     const hue = tinycolor(getAccentColorForUsername(name)).toHsl().h
52     UserAvatarHueCache.set(name, hue)
53     return hue
54   }, [color, name])
56   const letter = useMemo(() => {
57     return name.substring(0, 1).toUpperCase()
58   }, [name])
60   return (
61     <div
62       ref={ref}
63       className={clsx(
64         'h-custom w-custom relative flex items-center justify-center overflow-hidden rounded-lg',
65         className,
66       )}
67       style={
68         {
69           fontSize: '0.75rem',
70           lineHeight: '1.333',
71           fontWeight: 600,
72           backgroundColor: `hsl(${hue}, 100%, 90%)`,
73           color: `hsl(${hue}, 100%, 10%)`,
74           userSelect: 'none',
75           borderRadius: '0.5rem',
76           '--h-custom': '1.75rem',
77           '--w-custom': '1.75rem',
78         } as React.CSSProperties
79       }
80       {...rest}
81     >
82       {letter}
83     </div>
84   )