UNPKG

@spark-ui/components

Version:

Spark (Leboncoin design system) components.

267 lines (258 loc) 7.95 kB
import { IconButton } from "../chunk-QNYSDG6F.mjs"; import "../chunk-7A5MVJB3.mjs"; import "../chunk-GAK4SC2F.mjs"; import { Icon } from "../chunk-UMUMFMFB.mjs"; import "../chunk-KEGAAGJW.mjs"; import { Slot } from "../chunk-6QCEPQ3U.mjs"; // src/avatar/Avatar.tsx import { cx } from "class-variance-authority"; import * as React2 from "react"; // src/avatar/context.ts import * as React from "react"; var AvatarContext = React.createContext(void 0); var useAvatarContext = () => { const context = React.useContext(AvatarContext); if (!context) { throw new Error("useAvatarContext must be used within an Avatar component"); } return context; }; // src/avatar/Avatar.tsx import { jsx } from "react/jsx-runtime"; var sizeMap = { xs: 24, sm: 32, md: 40, lg: 56, xl: 64, // default "2xl": 96 }; var Avatar = React2.forwardRef( ({ className, size = "xl", isOnline = false, onlineText, username, asChild, children, design = "circle", ...props }, ref) => { const Comp = asChild ? Slot : "div"; const contextValue = React2.useMemo( () => ({ size, isOnline, onlineText, username, design, pixelSize: sizeMap[size] }), [size, isOnline, username, design, onlineText] ); return /* @__PURE__ */ jsx(AvatarContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx( Comp, { ref, style: { width: sizeMap[size], height: sizeMap[size] }, "data-spark-component": "avatar", className: cx("relative inline-flex items-center justify-center", className), ...props, children } ) }); } ); Avatar.displayName = "Avatar"; // src/avatar/AvatarImage.tsx import { cx as cx2 } from "class-variance-authority"; import { useState } from "react"; import { jsx as jsx2 } from "react/jsx-runtime"; var AvatarImage = ({ className, asChild, src, ...props }) => { const { username, isOnline, onlineText } = useAvatarContext(); const Comp = asChild ? Slot : "img"; const [isVisible, setIsVisible] = useState(false); const accessibleName = isOnline && onlineText ? `${username} (${onlineText})` : username; return /* @__PURE__ */ jsx2( Comp, { "aria-hidden": true, className: cx2( "absolute inset-0 size-full", "object-cover", { "transition-all duration-300 group-hover:scale-120": props.onClick }, "focus-visible:u-outline", isVisible ? "block" : "hidden", className ), alt: accessibleName, src, onLoad: () => { setIsVisible(true); }, ...props } ); }; AvatarImage.displayName = "AvatarImage"; // src/avatar/AvatarAction.tsx import { PenOutline } from "@spark-ui/icons/PenOutline"; import { cx as cx3 } from "class-variance-authority"; import { jsx as jsx3 } from "react/jsx-runtime"; var AvatarAction = ({ className, children, asChild, angle = 135, ariaLabel, ...props }) => { const Comp = asChild ? Slot : IconButton; const { pixelSize, design } = useAvatarContext(); function getBadgePosition(circleSize) { const angleRad = (90 - angle) * Math.PI / 180; const circleRadius = circleSize / 2; return { x: circleRadius + circleRadius * Math.cos(angleRad), y: circleRadius - circleRadius * Math.sin(angleRad) }; } const position = getBadgePosition(pixelSize); const isCustomElement = asChild; return /* @__PURE__ */ jsx3( Comp, { "data-spark-component": "avatar-action", style: { position: "absolute", ...design === "circle" ? { left: `${position.x}px`, top: `${position.y}px` } : {}, ...design === "square" ? { right: "0px", bottom: "0px" } : {} }, className: cx3( "z-raised", design === "circle" ? "-translate-x-1/2 -translate-y-1/2" : "translate-x-1/4 translate-y-1/4", { "shadow-sm": !isCustomElement }, className ), "aria-label": ariaLabel, title: ariaLabel, ...!isCustomElement ? { size: "sm", intent: "support", design: "contrast" } : {}, ...props, children: children || /* @__PURE__ */ jsx3(Icon, { size: "sm", children: /* @__PURE__ */ jsx3(PenOutline, {}) }) } ); }; AvatarAction.displayName = "AvatarAction"; // src/avatar/AvatarOnlineBadge.tsx import { cx as cx4 } from "class-variance-authority"; import { jsx as jsx4 } from "react/jsx-runtime"; var AvatarOnlineBadge = ({ angle = 135, ...props }) => { const { isOnline, pixelSize, design, onlineText, size } = useAvatarContext(); if (!isOnline) return null; function getBadgePosition(circleSize) { const angleRad = (90 - angle) * Math.PI / 180; const circleRadius = circleSize / 2; return { x: circleRadius + circleRadius * Math.cos(angleRad), y: circleRadius - circleRadius * Math.sin(angleRad) }; } const badgePosition = getBadgePosition(pixelSize); return /* @__PURE__ */ jsx4( "div", { "data-spark-component": "avatar-online-badge", role: "status", "aria-label": onlineText, style: { ...design === "circle" ? { left: `${badgePosition.x}px`, top: `${badgePosition.y}px` } : { right: "0px", bottom: "0px" } }, className: cx4( "bg-success outline-surface absolute rounded-full", design === "circle" ? "-translate-x-1/2 -translate-y-1/2" : "translate-x-1/4 translate-y-1/4", ["lg", "xl", "2xl"].includes(size) ? cx4("size-sz-12 outline-4") : cx4("size-sz-8 outline-2") ), ...props } ); }; AvatarOnlineBadge.displayName = "AvatarOnlineBadge"; // src/avatar/AvatarUser.tsx import { cx as cx5 } from "class-variance-authority"; import { jsx as jsx5 } from "react/jsx-runtime"; var AvatarUser = ({ asChild, children, className, ...props }) => { const { design, isOnline, onlineText, username } = useAvatarContext(); const Comp = asChild ? Slot : "div"; const accessibleName = isOnline && onlineText ? `${username} (${onlineText})` : username; return /* @__PURE__ */ jsx5( Comp, { ...!asChild && { role: "img" }, "aria-label": accessibleName, title: accessibleName, className: cx5( "group default:border-outline relative size-full overflow-hidden", "focus-visible:u-outline", { "default:rounded-full": design === "circle", "default:rounded-md": design === "square", "hover:opacity-dim-1 cursor-pointer": asChild || props.onClick }, className ), ...props, children } ); }; AvatarUser.displayName = "AvatarUser"; // src/avatar/AvatarPlaceholder.tsx import { cx as cx6 } from "class-variance-authority"; import { jsx as jsx6 } from "react/jsx-runtime"; var AvatarPlaceholder = ({ className, children, ...props }) => { const { size, username } = useAvatarContext(); const firstLetter = username?.charAt(0); return /* @__PURE__ */ jsx6( "div", { "aria-hidden": true, className: cx6( "absolute inset-0 flex size-full items-center justify-center", "default:bg-neutral default:text-on-neutral", { "text-display-1": size === "2xl", "text-display-2": ["xl", "lg"].includes(size), "text-display-3": size === "md", "text-headline-2": size === "sm", "text-body-2 font-bold": size === "xs" }, className ), ...props, children: children || firstLetter } ); }; AvatarPlaceholder.displayName = "AvatarPlaceholder"; // src/avatar/index.ts var AvatarComponent = Avatar; AvatarComponent.Image = AvatarImage; AvatarComponent.Action = AvatarAction; AvatarComponent.OnlineBadge = AvatarOnlineBadge; AvatarComponent.User = AvatarUser; AvatarComponent.Placeholder = AvatarPlaceholder; export { AvatarComponent as Avatar }; //# sourceMappingURL=index.mjs.map