UNPKG

@trail-ui/react

Version:
145 lines (142 loc) 4.75 kB
import { AvatarIcon } from "./chunk-B63AQA6W.mjs"; // src/avatar/avatar.tsx import { useImage } from "@trail-ui/hooks"; import { clsx, dataAttr } from "@trail-ui/shared-utils"; import { avatar } from "@trail-ui/theme"; import { filterDOMProps } from "@react-aria/utils"; import { createContext, forwardRef, useMemo } from "react"; import { mergeProps, useFocusRing, useHover } from "react-aria"; import { Button, Tooltip, TooltipTrigger, useContextProps } from "react-aria-components"; import { jsx, jsxs } from "react/jsx-runtime"; var safeText = (name) => { const parts = name.trim().split(" "); if (parts.length === 1) { return parts[0].slice(0, 2).toUpperCase(); } else { return (parts[0][0] + parts[1][0]).toUpperCase(); } }; var AvatarContext = createContext({}); function Avatar(props, ref) { [props, ref] = useContextProps(props, ref, AvatarContext); const ctx = props; const { elementType, src, name, icon = /* @__PURE__ */ jsx(AvatarIcon, {}), className, classNames, fallback: fallbackComponent, alt = name || "avatar", color = "red", radius = "full", size = "md", isBordered = false, isDisabled = false, ignoreFallback = false, showFallback: showFallbackProp = false, getInitials = safeText, ImgComponent = "img", imgProps, onError, onClick, ...avatarProps } = props; const Component = elementType || "span"; const { isFocusVisible, isFocused, focusProps } = useFocusRing(); const { isHovered, hoverProps } = useHover({ isDisabled }); const imageStatus = useImage({ src, onError, ignoreFallback }); const isImgLoaded = imageStatus === "loaded"; const showFallback = (!src || !isImgLoaded) && showFallbackProp; const slots = useMemo( () => { var _a; return avatar({ color, radius, size, isBordered, isDisabled, isInGroup: ctx == null ? void 0 : ctx.isInGroup, isInGridGroup: (_a = ctx == null ? void 0 : ctx.isGrid) != null ? _a : false }); }, [color, radius, size, isBordered, isDisabled, ctx == null ? void 0 : ctx.isInGroup, ctx == null ? void 0 : ctx.isGrid] ); const baseStyles = clsx(classNames == null ? void 0 : classNames.base, className); const fallback = useMemo(() => { if (!showFallback && src) return null; if (fallbackComponent) { return /* @__PURE__ */ jsx( "div", { "aria-label": alt, className: slots.fallback({ class: classNames == null ? void 0 : classNames.fallback }), role: "img", children: fallbackComponent } ); } return name ? /* @__PURE__ */ jsx("span", { "aria-label": alt, className: slots.name({ class: classNames == null ? void 0 : classNames.name }), role: "img", children: getInitials(name) }) : /* @__PURE__ */ jsx("span", { "aria-label": alt, className: slots.icon({ class: classNames == null ? void 0 : classNames.icon }), role: "img", children: icon }); }, [showFallback, src, fallbackComponent, classNames, name, icon, alt, slots, getInitials]); return /* @__PURE__ */ jsxs(TooltipTrigger, { delay: 200, closeDelay: 200, children: [ /* @__PURE__ */ jsx( Button, { isDisabled, className: `${isDisabled ? "pointer-events-none cursor-default" : ""} focus-visible:rounded-full focus-visible:outline focus-visible:outline-2 focus-visible:outline-purple-600`, onPress: onClick, children: /* @__PURE__ */ jsxs( Component, { ...mergeProps(filterDOMProps(avatarProps), focusProps, hoverProps), ref, "data-hovered": dataAttr(isHovered), "data-focused": dataAttr(isFocused), "data-focus-visible": dataAttr(isFocusVisible), className: slots.base({ class: baseStyles }), children: [ src && /* @__PURE__ */ jsx( ImgComponent, { src, alt, "data-loaded": dataAttr(isImgLoaded), className: slots.img({ class: classNames == null ? void 0 : classNames.img }), ...imgProps } ), fallback ] } ) } ), /* @__PURE__ */ jsx( Tooltip, { className: "shadow-medium pointer-events-none mt-1 rounded bg-neutral-900 text-neutral-50 dark:bg-neutral-900 dark:text-neutral-50", placement: "bottom", children: /* @__PURE__ */ jsx("p", { className: "px-2 py-1 text-[10px]", children: alt }) } ) ] }); } var _Avatar = forwardRef(Avatar); export { AvatarContext, _Avatar };