diff --git a/src/components/Avatar/Avatar.module.css b/src/components/Avatar/Avatar.module.css index df4d6e0d..f27442a7 100644 --- a/src/components/Avatar/Avatar.module.css +++ b/src/components/Avatar/Avatar.module.css @@ -16,80 +16,75 @@ limitations under the License. .avatar { display: inline-block; - aspect-ratio: 1 / 1; - width: var(--cpd-avatar-size); + box-sizing: border-box; line-height: var(--cpd-avatar-size); text-align: center; - font-size: min(calc(var(--cpd-avatar-size) * 0.75), 60px); - border-radius: var(--cpd-avatar-radius); + font-size: min(calc(var(--cpd-avatar-size) * 0.5625), 60px); text-transform: uppercase; speak: none; - pointer-events: none; - font-weight: normal; + font-weight: bold; overflow: hidden; user-select: none; } -img.avatar { +.avatar, +.image { + aspect-ratio: 1 / 1; + width: var(--cpd-avatar-size); + border-radius: var(--cpd-avatar-radius); +} + +.image { object-fit: cover; overflow: hidden; } -.avatar:not([src]) { +.avatar:not(:has(.image)) { /* In the future we'd prefer to pass the HEX code as the data attr and use `attr(data-color)` to avoid the style declaration from below but this is currently not supported in all browsers */ background: var(--cpd-avatar-bg); - border: 1px solid var(--cpd-avatar-border); color: var(--cpd-avatar-color); } .avatar[data-color] { --cpd-avatar-bg: var(--cpd-color-blue-300); - --cpd-avatar-border: var(--cpd-color-blue-400); - --cpd-avatar-color: var(--cpd-color-blue-900); + --cpd-avatar-color: var(--cpd-color-blue-1200); } .avatar[data-color="2"] { --cpd-avatar-bg: var(--cpd-color-fuchsia-300); - --cpd-avatar-border: var(--cpd-color-fuchsia-400); - --cpd-avatar-color: var(--cpd-color-fuchsia-900); + --cpd-avatar-color: var(--cpd-color-fuchsia-1200); } .avatar[data-color="3"] { --cpd-avatar-bg: var(--cpd-color-green-300); - --cpd-avatar-border: var(--cpd-color-green-400); - --cpd-avatar-color: var(--cpd-color-green-900); + --cpd-avatar-color: var(--cpd-color-green-1200); } .avatar[data-color="4"] { --cpd-avatar-bg: var(--cpd-color-pink-300); - --cpd-avatar-border: var(--cpd-color-pink-400); - --cpd-avatar-color: var(--cpd-color-pink-900); + --cpd-avatar-color: var(--cpd-color-pink-1200); } .avatar[data-color="5"] { --cpd-avatar-bg: var(--cpd-color-orange-300); - --cpd-avatar-border: var(--cpd-color-orange-400); - --cpd-avatar-color: var(--cpd-color-orange-900); + --cpd-avatar-color: var(--cpd-color-orange-1200); } .avatar[data-color="6"] { --cpd-avatar-bg: var(--cpd-color-cyan-300); - --cpd-avatar-border: var(--cpd-color-cyan-400); - --cpd-avatar-color: var(--cpd-color-cyan-900); + --cpd-avatar-color: var(--cpd-color-cyan-1200); } .avatar[data-color="7"] { --cpd-avatar-bg: var(--cpd-color-purple-300); - --cpd-avatar-border: var(--cpd-color-purple-400); - --cpd-avatar-color: var(--cpd-color-purple-900); + --cpd-avatar-color: var(--cpd-color-purple-1200); } .avatar[data-color="8"] { --cpd-avatar-bg: var(--cpd-color-lime-300); - --cpd-avatar-border: var(--cpd-color-lime-400); - --cpd-avatar-color: var(--cpd-color-lime-900); + --cpd-avatar-color: var(--cpd-color-lime-1200); } .avatar[data-type="round"] { diff --git a/src/components/Avatar/Avatar.tsx b/src/components/Avatar/Avatar.tsx index 0ea09c5b..4d1dd288 100644 --- a/src/components/Avatar/Avatar.tsx +++ b/src/components/Avatar/Avatar.tsx @@ -15,60 +15,68 @@ limitations under the License. */ import classnames from "classnames"; -import React, { Suspense } from "react"; +import React, { Suspense, forwardRef } from "react"; import { getInitialLetter } from "../../utils/string"; import { SuspenseImg } from "../../utils/SuspenseImg"; import styles from "./Avatar.module.css"; import { useIdColorHash } from "./useIdColorHash"; -type AvatarProps = { - src?: string; +type AvatarProps = JSX.IntrinsicElements["span"] & { + src?: React.ComponentProps["src"]; id: string; name: string; type?: "square" | "round"; - className?: string; size?: CSSStyleDeclaration["height"]; + onError?: React.ComponentProps["onError"]; }; -export const Avatar: React.FC = ({ - src, - id, - name = "", - type = "round", - className = "", - size, -}) => { +export const Avatar = forwardRef(function Avatar( + { + src, + id, + name = "", + type = "round", + className = "", + size, + onError, + ...props + }, + ref, +) { const hash = useIdColorHash(id); const style = { "--cpd-avatar-size": size, } as React.CSSProperties; - const imagelessAvatar = ( + const fallbackInitial = <>{getInitialLetter(name)}; + + return ( - {getInitialLetter(name)} + {!src ? ( + fallbackInitial + ) : ( + + + + )} ); - - return !src ? ( - imagelessAvatar - ) : ( - - - - ); -}; +}); diff --git a/src/utils/SuspenseImg.tsx b/src/utils/SuspenseImg.tsx index 1d7750b8..3e4aeae0 100644 --- a/src/utils/SuspenseImg.tsx +++ b/src/utils/SuspenseImg.tsx @@ -42,9 +42,9 @@ const imgCache = { }, }; -type SuspenseImgProps = { +type SuspenseImgProps = JSX.IntrinsicElements["img"] & { src: string; -} & React.ImgHTMLAttributes; +}; export const SuspenseImg: React.FC = ({ src, ...props }) => { /**