@spark-ui/components
Version:
Spark (Leboncoin design system) components.
1 lines • 14.5 kB
Source Map (JSON)
{"version":3,"sources":["../../src/avatar/Avatar.tsx","../../src/avatar/context.ts","../../src/avatar/AvatarImage.tsx","../../src/avatar/AvatarAction.tsx","../../src/avatar/AvatarOnlineBadge.tsx","../../src/avatar/AvatarUser.tsx","../../src/avatar/AvatarPlaceholder.tsx","../../src/avatar/index.ts"],"sourcesContent":["import { cx } from 'class-variance-authority'\nimport * as React from 'react'\n\nimport { Slot } from '../slot'\nimport { AvatarContext } from './context'\nimport type { AvatarProps } from './types'\n\nconst sizeMap = {\n xs: 24,\n sm: 32,\n md: 40,\n lg: 56,\n xl: 64, // default\n '2xl': 96,\n}\n\nexport const Avatar = React.forwardRef<HTMLDivElement, AvatarProps>(\n (\n {\n className,\n size = 'xl',\n isOnline = false,\n onlineText,\n username,\n asChild,\n children,\n design = 'circle',\n ...props\n },\n ref\n ) => {\n const Comp = asChild ? Slot : 'div'\n const contextValue = React.useMemo(\n () => ({\n size,\n isOnline,\n onlineText,\n username,\n design,\n pixelSize: sizeMap[size],\n }),\n [size, isOnline, username, design, onlineText]\n )\n\n return (\n <AvatarContext.Provider value={contextValue}>\n <Comp\n ref={ref}\n style={{\n width: sizeMap[size],\n height: sizeMap[size],\n }}\n data-spark-component=\"avatar\"\n className={cx('relative inline-flex items-center justify-center', className)}\n {...props}\n >\n {children}\n </Comp>\n </AvatarContext.Provider>\n )\n }\n)\n\nAvatar.displayName = 'Avatar'\n","import * as React from 'react'\nimport type { AvatarContextValue } from './types'\n\nconst AvatarContext = React.createContext<AvatarContextValue | undefined>(undefined)\n\nexport const useAvatarContext = () => {\n const context = React.useContext(AvatarContext)\n if (!context) {\n throw new Error('useAvatarContext must be used within an Avatar component')\n }\n return context\n}\n\nexport { AvatarContext }\n","import { cx } from 'class-variance-authority'\nimport { useState } from 'react'\n\nimport { Slot } from '../slot'\nimport { useAvatarContext } from './context'\n\nexport interface AvatarImageProps extends React.ImgHTMLAttributes<HTMLImageElement> {\n asChild?: boolean\n}\n\nexport const AvatarImage = ({ className, asChild, src, ...props }: AvatarImageProps) => {\n const { username, isOnline, onlineText } = useAvatarContext()\n const Comp = asChild ? Slot : 'img'\n\n const [isVisible, setIsVisible] = useState(false)\n\n const accessibleName = isOnline && onlineText ? `${username} (${onlineText})` : username\n\n return (\n <Comp\n aria-hidden\n className={cx(\n 'absolute inset-0 size-full',\n 'object-cover',\n { 'transition-all duration-300 group-hover:scale-120': props.onClick },\n 'focus-visible:u-outline',\n isVisible ? 'block' : 'hidden',\n className\n )}\n alt={accessibleName}\n src={src}\n onLoad={() => {\n setIsVisible(true)\n }}\n {...props}\n />\n )\n}\n\nAvatarImage.displayName = 'AvatarImage'\n","import { PenOutline } from '@spark-ui/icons/PenOutline'\nimport { cx } from 'class-variance-authority'\n\nimport { Icon } from '../icon'\nimport { IconButton } from '../icon-button'\nimport { Slot } from '../slot'\nimport { useAvatarContext } from './context'\n\nexport interface AvatarActionProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n asChild?: boolean\n angle?: number\n ariaLabel: string\n}\n\nexport const AvatarAction = ({\n className,\n children,\n asChild,\n angle = 135,\n ariaLabel,\n ...props\n}: AvatarActionProps) => {\n const Comp = asChild ? Slot : IconButton\n const { pixelSize, design } = useAvatarContext()\n\n function getBadgePosition(circleSize: number) {\n const angleRad = ((90 - angle) * Math.PI) / 180\n const circleRadius = circleSize / 2\n\n return {\n x: circleRadius + circleRadius * Math.cos(angleRad),\n y: circleRadius - circleRadius * Math.sin(angleRad),\n }\n }\n\n const position = getBadgePosition(pixelSize)\n\n const isCustomElement = asChild\n\n return (\n <Comp\n data-spark-component=\"avatar-action\"\n style={{\n position: 'absolute',\n ...(design === 'circle' ? { left: `${position.x}px`, top: `${position.y}px` } : {}),\n ...(design === 'square' ? { right: '0px', bottom: '0px' } : {}),\n }}\n className={cx(\n 'z-raised',\n design === 'circle'\n ? '-translate-x-1/2 -translate-y-1/2'\n : 'translate-x-1/4 translate-y-1/4',\n { 'shadow-sm': !isCustomElement },\n className\n )}\n aria-label={ariaLabel}\n title={ariaLabel}\n {...(!isCustomElement ? { size: 'sm', intent: 'support', design: 'contrast' } : {})}\n {...props}\n >\n {children || (\n <Icon size=\"sm\">\n <PenOutline />\n </Icon>\n )}\n </Comp>\n )\n}\n\nAvatarAction.displayName = 'AvatarAction'\n","import { cx } from 'class-variance-authority'\nimport { ComponentPropsWithoutRef } from 'react'\n\nimport { useAvatarContext } from './context'\n\ninterface AvatarOnlineBadgeProps extends ComponentPropsWithoutRef<'div'> {\n angle?: number\n}\n\nexport const AvatarOnlineBadge = ({ angle = 135, ...props }: AvatarOnlineBadgeProps) => {\n const { isOnline, pixelSize, design, onlineText, size } = useAvatarContext()\n\n if (!isOnline) return null\n\n function getBadgePosition(circleSize: number) {\n const angleRad = ((90 - angle) * Math.PI) / 180\n const circleRadius = circleSize / 2\n\n return {\n x: circleRadius + circleRadius * Math.cos(angleRad),\n y: circleRadius - circleRadius * Math.sin(angleRad),\n }\n }\n\n const badgePosition = getBadgePosition(pixelSize)\n\n return (\n <div\n data-spark-component=\"avatar-online-badge\"\n role=\"status\"\n aria-label={onlineText}\n style={{\n ...(design === 'circle'\n ? { left: `${badgePosition.x}px`, top: `${badgePosition.y}px` }\n : { right: '0px', bottom: '0px' }),\n }}\n className={cx(\n 'bg-success outline-surface absolute rounded-full',\n design === 'circle'\n ? '-translate-x-1/2 -translate-y-1/2'\n : 'translate-x-1/4 translate-y-1/4',\n ['lg', 'xl', '2xl'].includes(size) ? cx('size-sz-12 outline-4') : cx('size-sz-8 outline-2')\n )}\n {...props}\n />\n )\n}\n\nAvatarOnlineBadge.displayName = 'AvatarOnlineBadge'\n","import { cx } from 'class-variance-authority'\n\nimport { Slot } from '../slot'\nimport { useAvatarContext } from './context'\n\nexport interface AvatarImageProps extends React.ImgHTMLAttributes<HTMLDivElement> {\n asChild?: boolean\n}\n\nexport const AvatarUser = ({ asChild, children, className, ...props }: AvatarImageProps) => {\n const { design, isOnline, onlineText, username } = useAvatarContext()\n const Comp = asChild ? Slot : 'div'\n\n const accessibleName = isOnline && onlineText ? `${username} (${onlineText})` : username\n\n return (\n <Comp\n {...(!asChild && { role: 'img' })}\n aria-label={accessibleName}\n title={accessibleName}\n className={cx(\n 'group default:border-outline relative size-full overflow-hidden',\n 'focus-visible:u-outline',\n {\n 'default:rounded-full': design === 'circle',\n 'default:rounded-md': design === 'square',\n 'hover:opacity-dim-1 cursor-pointer': asChild || props.onClick,\n },\n className\n )}\n {...props}\n >\n {children}\n </Comp>\n )\n}\n\nAvatarUser.displayName = 'AvatarUser'\n","import { cx } from 'class-variance-authority'\n\nimport { useAvatarContext } from './context'\n\nexport interface AvatarPlaceholderProps extends React.ImgHTMLAttributes<HTMLDivElement> {\n className?: string\n children?: React.ReactNode\n}\n\nexport const AvatarPlaceholder = ({ className, children, ...props }: AvatarPlaceholderProps) => {\n const { size, username } = useAvatarContext()\n\n const firstLetter = username?.charAt(0)\n\n return (\n <div\n aria-hidden\n className={cx(\n 'absolute inset-0 flex size-full items-center justify-center',\n 'default:bg-neutral default:text-on-neutral',\n {\n 'text-display-1': size === '2xl',\n 'text-display-2': ['xl', 'lg'].includes(size),\n 'text-display-3': size === 'md',\n 'text-headline-2': size === 'sm',\n 'text-body-2 font-bold': size === 'xs',\n },\n className\n )}\n {...props}\n >\n {children || firstLetter}\n </div>\n )\n}\n\nAvatarPlaceholder.displayName = 'AvatarPlaceholder'\n","import { Avatar } from './Avatar'\nimport { AvatarImage } from './AvatarImage'\nimport { AvatarAction } from './AvatarAction'\nimport { AvatarOnlineBadge } from './AvatarOnlineBadge'\nimport { AvatarUser } from './AvatarUser'\nimport { AvatarPlaceholder } from './AvatarPlaceholder'\nimport type { AvatarProps } from './types'\n\nexport interface AvatarComponent\n extends React.ForwardRefExoticComponent<AvatarProps & React.RefAttributes<HTMLDivElement>> {\n Image: typeof AvatarImage\n Action: typeof AvatarAction\n OnlineBadge: typeof AvatarOnlineBadge\n User: typeof AvatarUser\n Placeholder: typeof AvatarPlaceholder\n}\n\nconst AvatarComponent = Avatar as AvatarComponent\n\nAvatarComponent.Image = AvatarImage\nAvatarComponent.Action = AvatarAction\nAvatarComponent.OnlineBadge = AvatarOnlineBadge\nAvatarComponent.User = AvatarUser\nAvatarComponent.Placeholder = AvatarPlaceholder\nexport { AvatarComponent as Avatar }\n"],"mappings":"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","names":["React","cx","jsx","cx","cx","jsx","cx","cx","jsx","cx","cx","jsx","cx","cx","jsx","cx"]}