@grasco/profile-picture 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/loadStyles.ts","../src/core/types.ts","../src/core/utils.ts","../src/core/styles.ts","../src/core/ProfilePicture.ts","../src/core/ProfilePictureGroup.ts","../src/wrappers/react/ProfilePictureGroup.tsx","../src/wrappers/react/index.ts","../src/index.ts"],"names":["LINK_ID","loaded","loadStyles","cssUrl","getCssUrl","link","metaUrl","currentScript","scriptUrl","SIZE_MAP","PRESENCE_COLORS","SHADOW_MAP","DEFAULTS","RADIUS_MAP","GROUP_DEFAULTS","cn","classes","isHexColor","color","getPositionClasses","position","getRibbonRotation","getInitials","text","words","getInitialsFontSize","containerSize","getBadgeSize","avatarSize","hasContent","size","fontSize","getPresenceSize","thickness","formatBadgeContent","content","max","createConicGradient","colors","i","start","end","hashString","str","hash","char","generateAvatarGradient","name","gradients","index","getGroupAvatarSize","calculateAvatarCounts","total","showAddButton","effectiveMax","visible","hidden","calculateStackPosition","overlap","_direction","spacing","step","calculateStackZIndex","direction","calculateGroupWidth","count","formatCounterText","getVariantClasses","variant","getBorderClasses","width","getBackgroundStyles","bgColor","bgGradient","getShadowStyles","shadow","keyframes","allKeyframes","baseStyles","componentStyles","shimmerStyles","getGlowShadow","intensity","r","g","b","groupKeyframes","groupBaseStyles","groupStyles","ProfilePicture","LitElement","style","sizeValue","changedProperties","bg","borderStyles","shadowStyles","glowStyles","glowColor","isInteractive","nothing","placeholderClass","html","styleMap","gradient","iconSize","ringWidth","ringGap","totalOffset","ringColor","offset","badgeSize","textColor","positionStyles","ribbonBg","ribbonColor","bgStyle","colorStyle","ribbonWidth","ribbonHeight","container","tabIndex","__decorateClass","property","state","customElement","groupStylesInjected","injectGroupStyles","ProfilePictureGroup","children","child","el","borderWidthAttr","borderWidth","user","event","target","hiddenUsers","handler","zIndex","e","rect","gap","top","left","status","showCounter","visibleUsers","elementCount","containerWidth","counterPosition","addButtonPosition","React","tooltip","dropdown","addButtonLabel","animated","onAvatarClick","onAvatarHover","onCounterClick","onDropdownItemClick","onAddClick","className","ref","elementRef","useRef","handleAvatarClick","useCallback","handleAvatarHover","handleCounterClick","customEvent","handleDropdownItemClick","handleAddClick","useEffect","element","src","alt","border","borderColor","ribbon","badge","loading","placeholder","placeholderColor","fallback","onLoad","onError"],"mappings":"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AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA,CAoCjBC,EAAAA,CAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA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","file":"index.js","sourcesContent":["/**\n * Idempotent CSS loader for @grasco/profile-picture\n *\n * Auto-injects the component's CSS via <link> tag when the module is imported.\n * Uses relative URL detection to find styles.css in the same directory as the JS file.\n *\n * Idempotency is guaranteed through 4 layers:\n * 1. Module-level flag - prevents multiple calls in same bundle\n * 2. ID check - prevents duplicates across bundles\n * 3. href pattern check - catches manually added links\n * 4. SSR guard - prevents errors in Node.js\n */\n\nconst LINK_ID = \"grasco-profile-picture-styles\";\n\nlet loaded = false;\n\n/**\n * Load the component's CSS stylesheet\n * Safe to call multiple times - will only inject once\n */\nexport function loadStyles(): void {\n // Skip if already loaded (module-level)\n if (loaded) {\n return;\n }\n\n // Skip if SSR (no document)\n if (typeof document === \"undefined\") {\n return;\n }\n\n // Skip if link already exists by ID (idempotency across bundles)\n if (document.getElementById(LINK_ID)) {\n loaded = true;\n return;\n }\n\n // Check if any link already points to our CSS (by href pattern)\n const existingLink = document.querySelector(\n 'link[href*=\"profile-picture\"][href$=\"styles.css\"]'\n );\n if (existingLink) {\n loaded = true;\n return;\n }\n\n // Get CSS URL relative to current script\n const cssUrl = getCssUrl();\n if (!cssUrl) {\n return;\n }\n\n // Inject link tag\n const link = document.createElement(\"link\");\n link.id = LINK_ID;\n link.rel = \"stylesheet\";\n link.href = cssUrl;\n document.head.appendChild(link);\n\n loaded = true;\n}\n\n/**\n * Get the CSS file URL based on the current script's location\n */\nfunction getCssUrl(): string | null {\n // Allow custom override via global variable\n if (\n typeof window !== \"undefined\" &&\n (window as unknown as Record<string, string>).__GRASCO_PROFILE_PICTURE_CSS__\n ) {\n return (window as unknown as Record<string, string>)\n .__GRASCO_PROFILE_PICTURE_CSS__;\n }\n\n // Try import.meta.url first (ESM - most reliable for bundlers)\n try {\n const metaUrl = import.meta.url;\n if (metaUrl) {\n const basePath = metaUrl.substring(0, metaUrl.lastIndexOf(\"/\") + 1);\n return `${basePath}styles.css`;\n }\n } catch {\n // import.meta.url not available\n }\n\n // Fallback: Get current script URL\n const currentScript = document.currentScript as HTMLScriptElement | null;\n if (currentScript?.src) {\n const scriptUrl = new URL(currentScript.src);\n const basePath = scriptUrl.href.substring(\n 0,\n scriptUrl.href.lastIndexOf(\"/\") + 1\n );\n return `${basePath}styles.css`;\n }\n\n return null;\n}\n","/**\n * Profile Picture Component - Type Definitions\n * Apple-inspired design system with modern 2025 aesthetics\n */\n\n// ─── Size System (Apple 8pt Grid) ─────────────────────────────────────────────\nexport type Size = \"2xs\" | \"xs\" | \"sm\" | \"md\" | \"lg\" | \"xl\" | \"2xl\" | \"3xl\";\n\n// Size presets in pixels (following 8pt grid)\nexport const SIZE_MAP: Record<Size, number> = {\n \"2xs\": 20, // Inline, compact UI\n xs: 24, // Small avatars, lists\n sm: 32, // Default list items\n md: 40, // Navigation, headers\n lg: 48, // Profile sections\n xl: 64, // Profile pages\n \"2xl\": 80, // Hero sections\n \"3xl\": 120, // Profile modals\n};\n\n// ─── Visual Variants ──────────────────────────────────────────────────────────\nexport type Variant = \"circle\" | \"rounded\" | \"squircle\" | \"square\";\n\n// ─── Positioning ──────────────────────────────────────────────────────────────\nexport type Position =\n | \"top-left\"\n | \"top-right\"\n | \"bottom-left\"\n | \"bottom-right\";\n\n// ─── Loading & Performance ────────────────────────────────────────────────────\nexport type LoadingStrategy = \"lazy\" | \"eager\";\nexport type PlaceholderType =\n | \"shimmer\"\n | \"pulse\"\n | \"blur\"\n | \"skeleton\"\n | \"none\";\n\n// ─── Presence / Status System ─────────────────────────────────────────────────\nexport type PresenceStatus = \"online\" | \"away\" | \"busy\" | \"offline\" | \"dnd\";\n\nexport interface PresenceConfig {\n /** Current status */\n status: PresenceStatus;\n /** Show animated ring */\n animate?: boolean;\n /** Ring thickness (1-3) */\n thickness?: 1 | 2 | 3;\n}\n\n// Status colors (Apple-inspired)\nexport const PRESENCE_COLORS: Record<PresenceStatus, string> = {\n online: \"#30D158\", // Apple Green\n away: \"#FFD60A\", // Apple Yellow\n busy: \"#FF453A\", // Apple Red\n offline: \"#8E8E93\", // Apple Gray\n dnd: \"#FF453A\", // Apple Red (Do Not Disturb)\n};\n\n// ─── Ribbon Configuration ─────────────────────────────────────────────────────\nexport interface RibbonConfig {\n /** Text displayed on the ribbon */\n text: string;\n /** Position of the ribbon */\n position?: Position;\n /** Text color (CSS color) */\n color?: string;\n /** Background color (CSS color or gradient) */\n bgColor?: string;\n /** Icon before text (emoji or symbol) */\n icon?: string;\n}\n\n// ─── Badge Configuration ──────────────────────────────────────────────────────\nexport interface BadgeConfig {\n /** Badge content (text, number, or empty for dot) */\n content?: string | number;\n /** Position of the badge */\n position?: Position;\n /** Text/icon color */\n color?: string;\n /** Background color */\n bgColor?: string;\n /** Enable pulse animation */\n pulse?: boolean;\n /** Enable glow effect */\n glow?: boolean;\n /** Max value to display (shows 99+ if exceeded) */\n max?: number;\n}\n\n// ─── Glow Effect ──────────────────────────────────────────────────────────────\nexport interface GlowConfig {\n /** Glow color (defaults to border or bg color) */\n color?: string;\n /** Intensity (0-1) */\n intensity?: number;\n /** Animate the glow */\n animate?: boolean;\n}\n\n// ─── Ring Effect (like Instagram stories) ────────────────────────────────────\nexport interface RingConfig {\n /** Show ring */\n show: boolean;\n /** Ring color or gradient */\n color?: string;\n /** Gradient colors for multi-color ring */\n gradient?: string[];\n /** Ring width */\n width?: number;\n /** Gap between ring and avatar */\n gap?: number;\n /** Animate (rotate for gradient) */\n animate?: boolean;\n}\n\n// ─── Interactive States ───────────────────────────────────────────────────────\nexport interface InteractionConfig {\n /** Enable hover effects */\n hoverable?: boolean;\n /** Enable press/click effects */\n pressable?: boolean;\n /** Show focus ring on focus */\n focusable?: boolean;\n /** Cursor style */\n cursor?: \"pointer\" | \"default\" | \"zoom-in\";\n}\n\n// ─── Shadow Presets ───────────────────────────────────────────────────────────\nexport type ShadowPreset = \"none\" | \"sm\" | \"md\" | \"lg\" | \"glow\";\n\nexport const SHADOW_MAP: Record<ShadowPreset, string> = {\n none: \"none\",\n sm: \"0 1px 2px 0 rgba(0, 0, 0, 0.05)\",\n md: \"0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1)\",\n lg: \"0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1)\",\n glow: \"0 0 20px 0 rgba(99, 102, 241, 0.3)\",\n};\n\n// ─── Animation Presets ────────────────────────────────────────────────────────\nexport type AnimationPreset = \"none\" | \"fade\" | \"scale\" | \"slide\" | \"bounce\";\n\n// ─── Default Values ───────────────────────────────────────────────────────────\nexport const DEFAULTS = {\n size: \"md\" as Size,\n variant: \"circle\" as Variant,\n loading: \"lazy\" as LoadingStrategy,\n placeholder: \"shimmer\" as PlaceholderType,\n borderWidth: 2 as const,\n borderColor: \"#ffffff\",\n placeholderColor: \"#f3f4f6\",\n shadow: \"sm\" as ShadowPreset,\n animation: \"fade\" as AnimationPreset,\n} as const;\n\n// ─── CSS Custom Properties (for theming) ──────────────────────────────────────\nexport const CSS_VARS = {\n \"--pp-transition-duration\": \"200ms\",\n \"--pp-transition-timing\": \"cubic-bezier(0.4, 0, 0.2, 1)\",\n \"--pp-spring-timing\": \"cubic-bezier(0.34, 1.56, 0.64, 1)\",\n \"--pp-hover-scale\": \"1.05\",\n \"--pp-press-scale\": \"0.95\",\n \"--pp-focus-ring-color\": \"rgba(99, 102, 241, 0.5)\",\n \"--pp-focus-ring-width\": \"3px\",\n \"--pp-skeleton-base\": \"#e5e7eb\",\n \"--pp-skeleton-shine\": \"#f3f4f6\",\n} as const;\n\n// ─── Border Radius Presets ────────────────────────────────────────────────────\nexport const RADIUS_MAP: Record<Variant, string> = {\n circle: \"9999px\",\n rounded: \"12px\",\n squircle: \"30%\", // iOS app icon style\n square: \"0px\",\n};\n\n// ─── Full Component Props Interface ───────────────────────────────────────────\nexport interface ProfilePictureProps {\n // Core\n src?: string;\n alt?: string;\n\n // Sizing\n size?: Size | number;\n\n // Visual\n variant?: Variant;\n shadow?: ShadowPreset;\n\n // Border\n border?: boolean;\n borderWidth?: 1 | 2 | 3 | 4;\n borderColor?: string;\n\n // Background\n bgColor?: string;\n bgGradient?: string;\n\n // Effects\n glow?: GlowConfig;\n ring?: RingConfig;\n presence?: PresenceConfig;\n\n // Overlays\n ribbon?: RibbonConfig;\n badge?: BadgeConfig;\n\n // Loading\n loading?: LoadingStrategy;\n placeholder?: PlaceholderType;\n placeholderColor?: string;\n\n // Fallback\n fallback?: string;\n\n // Interaction\n interactive?: InteractionConfig;\n}\n\n// ─── Profile Picture Group Types ─────────────────────────────────────────────\n\n/** Direction for stacking avatars */\nexport type StackDirection = \"ltr\" | \"rtl\";\n\n/** Tooltip position relative to avatar */\nexport type TooltipPosition = \"top\" | \"bottom\" | \"left\" | \"right\";\n\n/** Tooltip configuration */\nexport interface TooltipConfig {\n /** Enable/disable tooltip (default: true) */\n enabled?: boolean;\n /** Position of tooltip relative to avatar */\n position?: TooltipPosition;\n /** Delay before showing tooltip in ms (default: 300) */\n delay?: number;\n}\n\n/** User data extracted from profile-picture elements */\nexport interface GroupUserData {\n /** User ID from data-user-id attribute */\n id?: string;\n /** User name from alt attribute */\n name: string;\n /** Image source URL */\n src?: string;\n /** Presence status from data-status attribute */\n status?: PresenceStatus;\n /** Reference to the profile-picture element */\n element: HTMLElement;\n /** Index in the group */\n index: number;\n\n // ─── Profile Picture Props (passed through from slotted elements) ──────────\n /** Visual variant (circle, rounded, squircle, square) */\n variant?: Variant;\n /** Shadow preset */\n shadow?: ShadowPreset;\n /** Show border */\n border?: boolean;\n /** Border width (1-4) */\n borderWidth?: 1 | 2 | 3 | 4;\n /** Border color */\n borderColor?: string;\n /** Background color */\n bgColor?: string;\n /** Background gradient */\n bgGradient?: string;\n}\n\n/** Dropdown configuration for overflow users */\nexport interface DropdownConfig {\n /** Max height of dropdown in px (default: 280) */\n maxHeight?: number;\n /** Show presence indicator dots (default: true) */\n showPresence?: boolean;\n /** Dropdown position (default: 'bottom') */\n position?: \"bottom\" | \"top\";\n}\n\n/** Profile Picture Group Props */\nexport interface ProfilePictureGroupProps {\n /** Maximum visible avatars before showing counter (default: 4) */\n max?: number;\n /** Stack direction - ltr shows first on left (default: 'ltr') */\n direction?: StackDirection;\n /** Overlap amount as percentage 0-1 (default: 0.3) */\n overlap?: number;\n /** Avatar size - inherited by children (default: 'md') */\n size?: Size | number;\n /** Spacing between avatars in px (overrides overlap calculation) */\n spacing?: number;\n /** Tooltip configuration */\n tooltip?: TooltipConfig;\n /** Dropdown configuration for overflow users */\n dropdown?: DropdownConfig;\n /** Show add button (default: false) */\n showAddButton?: boolean;\n /** Add button label for accessibility */\n addButtonLabel?: string;\n /** Enable hover lift animation (default: true) */\n animated?: boolean;\n}\n\n/** Group component defaults */\nexport const GROUP_DEFAULTS = {\n max: 4,\n direction: \"ltr\" as StackDirection,\n overlap: 0.3,\n size: \"md\" as Size,\n tooltipDelay: 300,\n dropdownMaxHeight: 280,\n animated: true,\n} as const;\n","/**\n * Profile Picture Component - Utility Functions\n * Apple-inspired design system utilities\n */\n\nimport type { Position, Size, Variant } from \"./types\";\nimport { RADIUS_MAP, SIZE_MAP } from \"./types\";\n\n/**\n * Resolve size to pixel value\n */\nexport function resolveSize(size: Size | number): number {\n if (typeof size === \"number\") {\n return size;\n }\n return SIZE_MAP[size] ?? SIZE_MAP.md;\n}\n\n/**\n * Merge class names, filtering out falsy values\n */\nexport function cn(...classes: (string | undefined | null | false)[]): string {\n return classes.filter(Boolean).join(\" \");\n}\n\n/**\n * Check if a color value is a hex code\n */\nexport function isHexColor(color: string): boolean {\n return /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/.test(color);\n}\n\n/**\n * Check if a value is a CSS color (not a Tailwind class)\n */\nexport function isCssColor(value: string): boolean {\n if (isHexColor(value)) {\n return true;\n }\n if (/^(rgb|hsl|oklch|oklab|lab|lch)a?\\s*\\(/.test(value)) {\n return true;\n }\n if (value.includes(\"gradient\")) {\n return true;\n }\n const namedColors = [\n \"transparent\",\n \"currentColor\",\n \"inherit\",\n \"white\",\n \"black\",\n ];\n return namedColors.includes(value.toLowerCase());\n}\n\n/**\n * Get position classes for overlays (ribbon, badge)\n */\nexport function getPositionClasses(position: Position): string {\n const positions: Record<Position, string> = {\n \"top-left\": \"np:top-0 np:left-0\",\n \"top-right\": \"np:top-0 np:right-0\",\n \"bottom-left\": \"np:bottom-0 np:left-0\",\n \"bottom-right\": \"np:bottom-0 np:right-0\",\n };\n return positions[position];\n}\n\n/**\n * Get ribbon rotation based on position\n */\nexport function getRibbonRotation(position: Position): string {\n const rotations: Record<Position, string> = {\n \"top-left\": \"np:-rotate-45 np:-translate-x-1/4 np:-translate-y-1/2\",\n \"top-right\": \"np:rotate-45 np:translate-x-1/4 np:-translate-y-1/2\",\n \"bottom-left\": \"np:rotate-45 np:-translate-x-1/4 np:translate-y-1/2\",\n \"bottom-right\": \"np:-rotate-45 np:translate-x-1/4 np:translate-y-1/2\",\n };\n return rotations[position];\n}\n\n/**\n * Generate initials from alt text for fallback\n * Apple-style: Single letter for single word, two letters for multiple\n */\nexport function getInitials(text: string): string {\n const cleaned = text.trim().replace(/[^\\w\\s]/g, \"\");\n const words = cleaned.split(/\\s+/).filter(Boolean);\n\n if (words.length === 0) {\n return \"?\";\n }\n if (words.length === 1) {\n return words[0].slice(0, 1).toUpperCase();\n }\n return (words[0][0] + words[words.length - 1][0]).toUpperCase();\n}\n\n/**\n * Get border radius value for variant\n */\nexport function getRadius(variant: Variant): string {\n return RADIUS_MAP[variant];\n}\n\n/**\n * Calculate optimal font size for initials based on container size\n */\nexport function getInitialsFontSize(containerSize: number): number {\n return Math.round(containerSize * 0.38);\n}\n\n/**\n * Calculate badge size relative to avatar size\n */\nexport function getBadgeSize(\n avatarSize: number,\n hasContent: boolean\n): { size: number; fontSize: number } {\n const baseRatio = hasContent ? 0.32 : 0.22;\n const size = Math.max(\n hasContent ? 18 : 10,\n Math.round(avatarSize * baseRatio)\n );\n const fontSize = Math.round(size * 0.6);\n return { size, fontSize };\n}\n\n/**\n * Calculate presence indicator size\n */\nexport function getPresenceSize(\n avatarSize: number,\n thickness: 1 | 2 | 3\n): number {\n const baseSize = Math.max(8, Math.round(avatarSize * 0.25));\n return baseSize + (thickness - 1) * 2;\n}\n\n/**\n * Format badge content (e.g., 99+ for large numbers)\n */\nexport function formatBadgeContent(\n content: string | number,\n max?: number\n): string {\n if (typeof content === \"string\") {\n return content;\n }\n if (max && content > max) {\n return `${max}+`;\n }\n return content.toString();\n}\n\n/**\n * Generate a gradient from colors array for ring effect\n */\nexport function createConicGradient(colors: string[]): string {\n if (colors.length === 0) {\n return \"transparent\";\n }\n if (colors.length === 1) {\n return colors[0];\n }\n\n const stops = colors.map((color, i) => {\n const start = (i / colors.length) * 360;\n const end = ((i + 1) / colors.length) * 360;\n return `${color} ${start}deg ${end}deg`;\n });\n\n return `conic-gradient(${stops.join(\", \")})`;\n}\n\n/**\n * Get contrast color for text on background\n * Returns white or black based on background luminance\n */\nexport function getContrastColor(bgColor: string): string {\n // Extract RGB values from hex\n if (!isHexColor(bgColor)) {\n return \"#ffffff\";\n }\n\n const hex = bgColor.replace(\"#\", \"\");\n const r = Number.parseInt(hex.slice(0, 2), 16);\n const g = Number.parseInt(hex.slice(2, 4), 16);\n const b = Number.parseInt(hex.slice(4, 6), 16);\n\n // Calculate relative luminance\n const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;\n\n return luminance > 0.5 ? \"#000000\" : \"#ffffff\";\n}\n\n/**\n * Clamp a number between min and max\n */\nexport function clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n}\n\n/**\n * Generate a stable hash from string for consistent random colors\n */\nexport function hashString(str: string): number {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash = (hash << 5) - hash + char;\n hash &= hash;\n }\n return Math.abs(hash);\n}\n\n/**\n * Generate a gradient from name for fallback backgrounds\n */\nexport function generateAvatarGradient(name: string): string {\n const gradients = [\n \"linear-gradient(135deg, #667eea 0%, #764ba2 100%)\",\n \"linear-gradient(135deg, #f093fb 0%, #f5576c 100%)\",\n \"linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)\",\n \"linear-gradient(135deg, #43e97b 0%, #38f9d7 100%)\",\n \"linear-gradient(135deg, #fa709a 0%, #fee140 100%)\",\n \"linear-gradient(135deg, #a8edea 0%, #fed6e3 100%)\",\n \"linear-gradient(135deg, #d299c2 0%, #fef9d7 100%)\",\n \"linear-gradient(135deg, #89f7fe 0%, #66a6ff 100%)\",\n \"linear-gradient(135deg, #cd9cf2 0%, #f6f3ff 100%)\",\n \"linear-gradient(135deg, #fddb92 0%, #d1fdff 100%)\",\n ];\n\n const index = hashString(name) % gradients.length;\n return gradients[index];\n}\n\n/**\n * Apply will-change optimization for animations\n */\nexport function getWillChangeProperty(\n hasAnimation: boolean,\n hasHover: boolean\n): string | undefined {\n if (!(hasAnimation || hasHover)) {\n return undefined;\n }\n const properties: string[] = [];\n if (hasAnimation) {\n properties.push(\"opacity\");\n }\n if (hasHover) {\n properties.push(\"transform\");\n }\n return properties.join(\", \");\n}\n\n/**\n * Check if user prefers reduced motion\n */\nexport function prefersReducedMotion(): boolean {\n if (typeof window === \"undefined\") {\n return false;\n }\n return window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n}\n\n// ─── Profile Picture Group Utilities ─────────────────────────────────────────\n\nimport type { GroupUserData, PresenceStatus, StackDirection } from \"./types\";\nimport { GROUP_DEFAULTS } from \"./types\";\n\n/**\n * Calculate the pixel size for group avatars\n */\nexport function getGroupAvatarSize(size: Size | number): number {\n if (typeof size === \"number\") {\n return size;\n }\n return SIZE_MAP[size] ?? SIZE_MAP[GROUP_DEFAULTS.size];\n}\n\n/**\n * Calculate visible and hidden avatar counts\n */\nexport function calculateAvatarCounts(\n total: number,\n max: number,\n showAddButton: boolean\n): { visible: number; hidden: number; showCounter: boolean } {\n const effectiveMax = showAddButton ? max - 1 : max;\n\n if (total <= effectiveMax) {\n return { visible: total, hidden: 0, showCounter: false };\n }\n\n // Show (max - 1) avatars + counter\n const visible = effectiveMax - 1;\n const hidden = total - visible;\n return { visible, hidden, showCounter: true };\n}\n\n/**\n * Calculate position offset for stacked avatars\n */\nexport function calculateStackPosition(\n index: number,\n avatarSize: number,\n overlap: number,\n _direction: StackDirection,\n spacing?: number\n): number {\n const step = spacing ?? avatarSize * (1 - overlap);\n const offset = index * step;\n\n // For RTL, we need to reverse the positioning\n // This is handled at the component level by reversing the order\n return offset;\n}\n\n/**\n * Calculate z-index for stacked avatars\n * First avatar (index 0) has highest z-index to appear on top\n */\nexport function calculateStackZIndex(\n index: number,\n total: number,\n direction: StackDirection\n): number {\n if (direction === \"ltr\") {\n // LTR: First item on top (highest z-index)\n return total - index;\n }\n // RTL: Last item on top\n return index + 1;\n}\n\n/**\n * Calculate the total width of the stacked group\n */\nexport function calculateGroupWidth(\n count: number,\n avatarSize: number,\n overlap: number,\n spacing?: number\n): number {\n if (count === 0) {\n return 0;\n }\n if (count === 1) {\n return avatarSize;\n }\n\n const step = spacing ?? avatarSize * (1 - overlap);\n return avatarSize + step * (count - 1);\n}\n\n/**\n * Extract user data from a profile-picture element\n */\nexport function extractUserData(\n element: HTMLElement,\n index: number\n): GroupUserData {\n return {\n id: element.getAttribute(\"data-user-id\") ?? undefined,\n name: element.getAttribute(\"alt\") ?? `User ${index + 1}`,\n src: element.getAttribute(\"src\") ?? undefined,\n status:\n (element.getAttribute(\"data-status\") as PresenceStatus) ?? undefined,\n element,\n index,\n };\n}\n\n/**\n * Extract all user data from child profile-picture elements\n */\nexport function extractAllUserData(container: HTMLElement): GroupUserData[] {\n const children = container.querySelectorAll(\"profile-picture\");\n return Array.from(children).map((el, index) =>\n extractUserData(el as HTMLElement, index)\n );\n}\n\n/**\n * Get initials for counter display (e.g., \"+5\")\n */\nexport function formatCounterText(count: number): string {\n if (count > 99) {\n return \"+99\";\n }\n return `+${count}`;\n}\n\n/**\n * Calculate tooltip position relative to avatar\n */\nexport function calculateTooltipPosition(\n avatarRect: DOMRect,\n tooltipWidth: number,\n tooltipHeight: number,\n position: \"top\" | \"bottom\" | \"left\" | \"right\" = \"top\",\n gap = 8\n): { top: number; left: number } {\n const { top, left, width, height } = avatarRect;\n const centerX = left + width / 2;\n const centerY = top + height / 2;\n\n switch (position) {\n case \"top\":\n return {\n top: top - tooltipHeight - gap,\n left: centerX - tooltipWidth / 2,\n };\n case \"bottom\":\n return {\n top: top + height + gap,\n left: centerX - tooltipWidth / 2,\n };\n case \"left\":\n return {\n top: centerY - tooltipHeight / 2,\n left: left - tooltipWidth - gap,\n };\n case \"right\":\n return {\n top: centerY - tooltipHeight / 2,\n left: left + width + gap,\n };\n }\n}\n\n/**\n * Clamp tooltip position within viewport\n */\nexport function clampTooltipPosition(\n position: { top: number; left: number },\n tooltipWidth: number,\n tooltipHeight: number,\n padding = 8\n): { top: number; left: number } {\n const viewport = {\n width: typeof window !== \"undefined\" ? window.innerWidth : 1920,\n height: typeof window !== \"undefined\" ? window.innerHeight : 1080,\n };\n\n return {\n top: clamp(\n position.top,\n padding,\n viewport.height - tooltipHeight - padding\n ),\n left: clamp(\n position.left,\n padding,\n viewport.width - tooltipWidth - padding\n ),\n };\n}\n","/**\n * Profile Picture Component - Styles & Animations\n * Apple-inspired design system with modern 2025 aesthetics\n */\n\nimport type { ShadowPreset, Variant } from \"./types\";\nimport { RADIUS_MAP, SHADOW_MAP } from \"./types\";\nimport { isHexColor } from \"./utils\";\n\n/**\n * Get variant-specific border radius styles\n */\nexport function getVariantStyles(variant: Variant): Record<string, string> {\n return { borderRadius: RADIUS_MAP[variant] };\n}\n\n/**\n * Get variant classes (Tailwind)\n */\nexport function getVariantClasses(variant: Variant): string {\n const variants: Record<Variant, string> = {\n circle: \"np:rounded-full\",\n rounded: \"np:rounded-xl\",\n squircle: \"np:rounded-[30%]\",\n square: \"np:rounded-none\",\n };\n return variants[variant];\n}\n\n/**\n * Get border styles\n */\nexport function getBorderClasses(\n width: 1 | 2 | 3 | 4,\n color: string\n): { className: string; style: Record<string, string> } {\n const widthClasses: Record<1 | 2 | 3 | 4, string> = {\n 1: \"np:border\",\n 2: \"np:border-2\",\n 3: \"np:border-[3px]\",\n 4: \"np:border-4\",\n };\n\n return {\n className: widthClasses[width],\n style: {\n borderColor: color,\n borderStyle: \"solid\",\n },\n };\n}\n\n/**\n * Get background styles (solid color or gradient)\n */\nexport function getBackgroundStyles(\n bgColor?: string,\n bgGradient?: string\n): { className: string; style?: Record<string, string> } {\n if (bgGradient) {\n return {\n className: \"\",\n style: { background: bgGradient },\n };\n }\n\n if (bgColor) {\n if (bgColor.includes(\"gradient\")) {\n return {\n className: \"\",\n style: { background: bgColor },\n };\n }\n return {\n className: \"\",\n style: { backgroundColor: bgColor },\n };\n }\n\n return { className: \"np:bg-gray-100\" };\n}\n\n/**\n * Get shadow styles\n */\nexport function getShadowStyles(shadow: ShadowPreset): Record<string, string> {\n return { boxShadow: SHADOW_MAP[shadow] };\n}\n\n/**\n * CSS Keyframe animations - Apple-inspired, physics-based\n */\nexport const keyframes = {\n // Shimmer loading effect\n shimmer: `\n@keyframes pp-shimmer {\n 0% { transform: translateX(-100%); }\n 100% { transform: translateX(100%); }\n}`,\n\n // Pulse animation (gentle breathe effect)\n pulse: `\n@keyframes pp-pulse {\n 0%, 100% { opacity: 1; transform: scale(1); }\n 50% { opacity: 0.7; transform: scale(0.98); }\n}`,\n\n // Skeleton loading pulse\n skeleton: `\n@keyframes pp-skeleton {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n}`,\n\n // Badge bounce entrance\n badgeBounce: `\n@keyframes pp-badge-bounce {\n 0% { transform: scale(0) translateY(10px); opacity: 0; }\n 50% { transform: scale(1.2) translateY(-2px); }\n 100% { transform: scale(1) translateY(0); opacity: 1; }\n}`,\n\n // Ring rotation (for gradient rings)\n ringRotate: `\n@keyframes pp-ring-rotate {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n}`,\n\n // Presence indicator pulse\n presencePulse: `\n@keyframes pp-presence-pulse {\n 0%, 100% { box-shadow: 0 0 0 0 currentColor; }\n 50% { box-shadow: 0 0 0 4px transparent; }\n}`,\n\n // Glow animation\n glow: `\n@keyframes pp-glow {\n 0%, 100% { box-shadow: 0 0 20px 0 var(--pp-glow-color, rgba(99, 102, 241, 0.3)); }\n 50% { box-shadow: 0 0 30px 5px var(--pp-glow-color, rgba(99, 102, 241, 0.5)); }\n}`,\n\n // Fade in\n fadeIn: `\n@keyframes pp-fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n}`,\n\n // Scale in (spring-like)\n scaleIn: `\n@keyframes pp-scale-in {\n 0% { transform: scale(0.8); opacity: 0; }\n 50% { transform: scale(1.05); }\n 100% { transform: scale(1); opacity: 1; }\n}`,\n};\n\n/**\n * All keyframes combined for injection\n */\nexport const allKeyframes = Object.values(keyframes).join(\"\\n\");\n\n/**\n * Component base styles\n */\nexport const baseStyles = `\n/* Profile Picture Component Styles */\n.pp-container {\n --pp-transition-duration: 200ms;\n --pp-transition-timing: cubic-bezier(0.4, 0, 0.2, 1);\n --pp-spring-timing: cubic-bezier(0.34, 1.56, 0.64, 1);\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n user-select: none;\n -webkit-user-select: none;\n flex-shrink: 0;\n}\n\n/* Inner container for image clipping - allows badges/rings to overflow */\n.pp-inner {\n position: absolute;\n inset: 0;\n overflow: hidden;\n border-radius: inherit;\n}\n\n/* Interactive states */\n.pp-interactive {\n cursor: pointer;\n transition: transform var(--pp-transition-duration) var(--pp-spring-timing),\n box-shadow var(--pp-transition-duration) var(--pp-transition-timing);\n}\n\n.pp-interactive:hover {\n transform: scale(1.05);\n}\n\n.pp-interactive:active {\n transform: scale(0.95);\n}\n\n.pp-interactive:focus-visible {\n outline: none;\n box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.5);\n}\n\n/* Image styles */\n.pp-image {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n object-fit: cover;\n transition: opacity var(--pp-transition-duration) var(--pp-transition-timing);\n}\n\n.pp-image-loading {\n opacity: 0;\n}\n\n.pp-image-loaded {\n opacity: 1;\n}\n\n/* Fallback styles */\n.pp-fallback {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n font-weight: 500;\n color: rgba(255, 255, 255, 0.9);\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);\n font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI', Roboto, sans-serif;\n letter-spacing: 0.02em;\n}\n\n.pp-fallback-icon {\n color: rgba(156, 163, 175, 0.8);\n}\n\n/* Shimmer placeholder */\n.pp-shimmer {\n position: absolute;\n inset: 0;\n overflow: hidden;\n}\n\n.pp-shimmer::after {\n content: '';\n position: absolute;\n inset: 0;\n background: linear-gradient(\n 90deg,\n transparent 0%,\n rgba(255, 255, 255, 0.4) 50%,\n transparent 100%\n );\n animation: pp-shimmer 1.5s infinite;\n}\n\n/* Pulse placeholder */\n.pp-pulse {\n animation: pp-pulse 2s ease-in-out infinite;\n}\n\n/* Skeleton placeholder */\n.pp-skeleton {\n background: linear-gradient(90deg, #e5e7eb 0%, #f3f4f6 50%, #e5e7eb 100%);\n background-size: 200% 100%;\n animation: pp-skeleton 1.5s ease-in-out infinite;\n}\n\n/* Badge styles */\n.pp-badge {\n position: absolute;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 9999px;\n font-weight: 600;\n font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', sans-serif;\n line-height: 1;\n animation: pp-badge-bounce 0.4s var(--pp-spring-timing);\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);\n border: 2px solid white;\n}\n\n.pp-badge-pulse {\n animation: pp-badge-bounce 0.4s var(--pp-spring-timing),\n pp-presence-pulse 2s ease-in-out infinite 0.4s;\n}\n\n.pp-badge-glow {\n box-shadow: 0 0 10px 2px var(--pp-badge-glow-color, currentColor);\n}\n\n/* Ribbon styles */\n.pp-ribbon-container {\n position: absolute;\n z-index: 10;\n overflow: hidden;\n}\n\n.pp-ribbon {\n position: absolute;\n width: 100%;\n text-align: center;\n font-weight: 600;\n font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', sans-serif;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);\n}\n\n/* Ring effect (Instagram-style) */\n.pp-ring {\n position: absolute;\n inset: -4px;\n border-radius: inherit;\n padding: 3px;\n background: var(--pp-ring-color, linear-gradient(45deg, #f09433, #e6683c, #dc2743, #cc2366, #bc1888));\n -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);\n mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);\n -webkit-mask-composite: xor;\n mask-composite: exclude;\n}\n\n.pp-ring-animated {\n animation: pp-ring-rotate 3s linear infinite;\n}\n\n/* Presence indicator */\n.pp-presence {\n position: absolute;\n bottom: 0;\n right: 0;\n border-radius: 9999px;\n border: 2px solid white;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);\n}\n\n.pp-presence-animated {\n animation: pp-presence-pulse 2s ease-in-out infinite;\n}\n\n/* Glow effect */\n.pp-glow {\n animation: pp-glow 2s ease-in-out infinite;\n}\n\n/* Reduced motion support */\n@media (prefers-reduced-motion: reduce) {\n .pp-container,\n .pp-interactive,\n .pp-image,\n .pp-shimmer::after,\n .pp-pulse,\n .pp-skeleton,\n .pp-badge,\n .pp-ring-animated,\n .pp-presence-animated,\n .pp-glow {\n animation: none !important;\n transition: none !important;\n }\n}\n`;\n\n/**\n * All styles combined (keyframes + base styles)\n */\nexport const componentStyles = `${allKeyframes}\\n${baseStyles}`;\n\n/**\n * Shimmer styles for inline injection (legacy support)\n */\nexport const shimmerStyles = `\n@keyframes np-shimmer {\n 0% { background-position: -200% 0; }\n 100% { background-position: 200% 0; }\n}\n.np-shimmer {\n background: linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.4) 50%, transparent 100%);\n background-size: 200% 100%;\n animation: np-shimmer 1.5s infinite;\n}\n`;\n\n/**\n * Generate glow shadow with custom color\n */\nexport function getGlowShadow(color: string, intensity = 0.3): string {\n if (isHexColor(color)) {\n // Convert hex to rgba\n const r = Number.parseInt(color.slice(1, 3), 16);\n const g = Number.parseInt(color.slice(3, 5), 16);\n const b = Number.parseInt(color.slice(5, 7), 16);\n return `0 0 20px 0 rgba(${r}, ${g}, ${b}, ${intensity})`;\n }\n return `0 0 20px 0 ${color}`;\n}\n\n/**\n * Get shimmer classes (legacy)\n */\nexport function getShimmerClasses(): string {\n return \"np-shimmer\";\n}\n\n// ─── Profile Picture Group Styles ────────────────────────────────────────────\n\n/**\n * Group component keyframe animations\n */\nexport const groupKeyframes = `\n@keyframes ppg-tooltip-in {\n from {\n opacity: 0;\n transform: translateY(4px) scale(0.96);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n}\n\n@keyframes ppg-dropdown-in {\n from {\n opacity: 0;\n transform: translateY(-8px) scale(0.96);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n}\n\n@keyframes ppg-avatar-lift {\n from {\n transform: translateY(0) scale(1);\n }\n to {\n transform: translateY(-4px) scale(1.08);\n }\n}\n`;\n\n/**\n * Group component base styles - Apple-inspired\n */\nexport const groupBaseStyles = `\n/* Profile Picture Group Container */\n.ppg-container {\n --ppg-transition: 200ms cubic-bezier(0.4, 0, 0.2, 1);\n --ppg-spring: 300ms cubic-bezier(0.34, 1.56, 0.64, 1);\n --ppg-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);\n --ppg-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.1);\n --ppg-shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.15);\n --ppg-radius: 12px;\n --ppg-counter-bg: #f5f5f7;\n --ppg-counter-text: #1d1d1f;\n --ppg-add-bg: #f5f5f7;\n --ppg-add-hover: #e8e8ed;\n --ppg-add-icon: #86868b;\n --ppg-border: rgba(0, 0, 0, 0.08);\n --ppg-tooltip-bg: rgba(29, 29, 31, 0.95);\n --ppg-tooltip-text: #ffffff;\n --ppg-dropdown-bg: #ffffff;\n --ppg-dropdown-hover: #f5f5f7;\n\n position: relative;\n display: inline-flex;\n align-items: center;\n isolation: isolate;\n}\n\n/* Avatar wrapper for positioning */\n.ppg-avatar-wrapper {\n position: absolute;\n top: 0;\n transition: transform var(--ppg-spring), z-index 0s;\n cursor: pointer;\n border-radius: 9999px;\n}\n\n.ppg-avatar-wrapper:focus-visible {\n outline: none;\n box-shadow: 0 0 0 3px rgba(0, 122, 255, 0.4);\n}\n\n/* Hover lift animation */\n.ppg-animated .ppg-avatar-wrapper:hover {\n z-index: 100 !important;\n animation: ppg-avatar-lift var(--ppg-spring) forwards;\n}\n\n.ppg-avatar-wrapper:hover {\n z-index: 100 !important;\n}\n\n/* Nested profile-picture styling */\n.ppg-avatar-wrapper profile-picture {\n display: block;\n width: 100%;\n height: 100%;\n border-radius: inherit;\n}\n\n/* Counter button */\n.ppg-counter {\n position: absolute;\n top: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 9999px;\n background: var(--ppg-counter-bg);\n color: var(--ppg-counter-text);\n font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', sans-serif;\n font-weight: 600;\n font-size: 13px;\n letter-spacing: -0.01em;\n cursor: pointer;\n border: none;\n box-shadow: 0 0 0 1.5px rgba(255, 255, 255, 0.95), var(--ppg-shadow-sm);\n transition: transform var(--ppg-spring), background-color var(--ppg-transition);\n user-select: none;\n -webkit-user-select: none;\n}\n\n.ppg-counter:hover {\n background: #e8e8ed;\n transform: scale(1.05);\n}\n\n.ppg-counter:active {\n transform: scale(0.98);\n}\n\n.ppg-counter:focus-visible {\n outline: none;\n box-shadow: 0 0 0 1.5px rgba(255, 255, 255, 0.95), 0 0 0 4px rgba(0, 122, 255, 0.4);\n}\n\n/* Add button */\n.ppg-add-button {\n position: absolute;\n top: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 9999px;\n background: var(--ppg-add-bg);\n border: 2px dashed var(--ppg-border);\n cursor: pointer;\n transition: all var(--ppg-spring);\n box-shadow: var(--ppg-shadow-sm);\n}\n\n.ppg-add-button:hover {\n background: var(--ppg-add-hover);\n border-color: rgba(0, 0, 0, 0.15);\n transform: scale(1.05);\n}\n\n.ppg-add-button:active {\n transform: scale(0.98);\n}\n\n.ppg-add-button:focus-visible {\n outline: none;\n box-shadow: 0 0 0 3px rgba(0, 122, 255, 0.4);\n}\n\n.ppg-add-icon {\n color: var(--ppg-add-icon);\n transition: color var(--ppg-transition);\n}\n\n.ppg-add-button:hover .ppg-add-icon {\n color: #1d1d1f;\n}\n\n/* Tooltip */\n.ppg-tooltip {\n position: fixed;\n z-index: 9999;\n padding: 6px 12px;\n background: var(--ppg-tooltip-bg);\n color: var(--ppg-tooltip-text);\n font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', sans-serif;\n font-size: 13px;\n font-weight: 500;\n border-radius: 8px;\n box-shadow: var(--ppg-shadow-lg);\n pointer-events: none;\n white-space: nowrap;\n animation: ppg-tooltip-in 150ms ease-out;\n backdrop-filter: blur(20px);\n -webkit-backdrop-filter: blur(20px);\n}\n\n.ppg-tooltip::after {\n content: '';\n position: absolute;\n width: 8px;\n height: 8px;\n background: inherit;\n transform: rotate(45deg);\n}\n\n.ppg-tooltip[data-position=\"top\"]::after {\n bottom: -4px;\n left: 50%;\n margin-left: -4px;\n}\n\n.ppg-tooltip[data-position=\"bottom\"]::after {\n top: -4px;\n left: 50%;\n margin-left: -4px;\n}\n\n/* Dropdown */\n.ppg-dropdown {\n position: absolute;\n z-index: 1000;\n min-width: 200px;\n max-width: 280px;\n background: var(--ppg-dropdown-bg);\n border-radius: var(--ppg-radius);\n box-shadow: var(--ppg-shadow-lg);\n border: 1px solid var(--ppg-border);\n overflow: hidden;\n animation: ppg-dropdown-in 200ms ease-out;\n}\n\n.ppg-dropdown[data-position=\"bottom\"] {\n top: calc(100% + 8px);\n}\n\n.ppg-dropdown[data-position=\"top\"] {\n bottom: calc(100% + 8px);\n}\n\n.ppg-dropdown-header {\n padding: 12px 16px 8px;\n font-size: 12px;\n font-weight: 600;\n color: #86868b;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n border-bottom: 1px solid var(--ppg-border);\n}\n\n.ppg-dropdown-list {\n overflow-y: auto;\n padding: 4px 0;\n}\n\n.ppg-dropdown-item {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 10px 16px;\n cursor: pointer;\n transition: background-color var(--ppg-transition);\n}\n\n.ppg-dropdown-item:hover {\n background: var(--ppg-dropdown-hover);\n}\n\n.ppg-dropdown-item:focus-visible {\n outline: none;\n background: var(--ppg-dropdown-hover);\n}\n\n.ppg-dropdown-avatar {\n flex-shrink: 0;\n width: 32px;\n height: 32px;\n border-radius: 9999px;\n object-fit: cover;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n}\n\n.ppg-dropdown-avatar-fallback {\n flex-shrink: 0;\n width: 32px;\n height: 32px;\n border-radius: 9999px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 13px;\n font-weight: 600;\n color: white;\n}\n\n.ppg-dropdown-info {\n flex: 1;\n min-width: 0;\n}\n\n.ppg-dropdown-name {\n font-size: 14px;\n font-weight: 500;\n color: #1d1d1f;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.ppg-dropdown-status {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n color: #86868b;\n margin-top: 2px;\n}\n\n.ppg-dropdown-presence {\n width: 8px;\n height: 8px;\n border-radius: 9999px;\n}\n\n.ppg-dropdown-presence[data-status=\"online\"] {\n background: #30D158;\n}\n\n.ppg-dropdown-presence[data-status=\"away\"] {\n background: #FFD60A;\n}\n\n.ppg-dropdown-presence[data-status=\"busy\"],\n.ppg-dropdown-presence[data-status=\"dnd\"] {\n background: #FF453A;\n}\n\n.ppg-dropdown-presence[data-status=\"offline\"] {\n background: #8E8E93;\n}\n\n/* Backdrop for dropdown */\n.ppg-backdrop {\n position: fixed;\n inset: 0;\n z-index: 999;\n}\n\n/* Reduced motion */\n@media (prefers-reduced-motion: reduce) {\n .ppg-container,\n .ppg-avatar-wrapper,\n .ppg-counter,\n .ppg-add-button,\n .ppg-tooltip,\n .ppg-dropdown {\n animation: none !important;\n transition: none !important;\n }\n\n .ppg-animated .ppg-avatar-wrapper:hover {\n animation: none !important;\n transform: none !important;\n }\n}\n\n/* Dark mode support */\n@media (prefers-color-scheme: dark) {\n .ppg-container {\n --ppg-counter-bg: #2c2c2e;\n --ppg-counter-text: #ffffff;\n --ppg-add-bg: #2c2c2e;\n --ppg-add-hover: #3a3a3c;\n --ppg-add-icon: #98989d;\n --ppg-border: rgba(255, 255, 255, 0.1);\n --ppg-dropdown-bg: #2c2c2e;\n --ppg-dropdown-hover: #3a3a3c;\n }\n\n .ppg-avatar-wrapper profile-picture {\n box-shadow: 0 0 6px 1.5px rgb(28 28 30 / 16%), var(--ppg-shadow-sm);\n }\n\n .ppg-counter {\n box-shadow: 0 0 0 1.5px rgba(28, 28, 30, 0.95), var(--ppg-shadow-sm);\n }\n\n .ppg-dropdown-name {\n color: #ffffff;\n }\n\n .ppg-dropdown-header {\n color: #98989d;\n border-color: rgba(255, 255, 255, 0.1);\n }\n}\n`;\n\n/**\n * All group styles combined\n */\nexport const groupStyles = `${groupKeyframes}\\n${groupBaseStyles}`;\n","/**\n * ProfilePicture Web Component\n * Apple-inspired design system with modern 2025 aesthetics\n *\n * A lightweight, framework-agnostic profile picture component\n * with advanced features: presence indicators, rings, badges, and ribbons.\n */\n\nimport { html, LitElement, nothing } from \"lit\";\nimport { customElement, property, state } from \"lit/decorators.js\";\nimport { styleMap } from \"lit/directives/style-map.js\";\nimport {\n componentStyles,\n getBackgroundStyles,\n getBorderClasses,\n getGlowShadow,\n getShadowStyles,\n getVariantClasses,\n shimmerStyles,\n} from \"./styles\";\nimport type {\n BadgeConfig,\n GlowConfig,\n InteractionConfig,\n LoadingStrategy,\n PlaceholderType,\n Position,\n PresenceConfig,\n RibbonConfig,\n RingConfig,\n ShadowPreset,\n Size,\n Variant,\n} from \"./types\";\nimport { DEFAULTS, PRESENCE_COLORS, RADIUS_MAP, SIZE_MAP } from \"./types\";\nimport {\n cn,\n createConicGradient,\n formatBadgeContent,\n generateAvatarGradient,\n getBadgeSize,\n getInitials,\n getInitialsFontSize,\n getPositionClasses,\n getPresenceSize,\n getRibbonRotation,\n isHexColor,\n} from \"./utils\";\n\n@customElement(\"profile-picture\")\nexport class ProfilePicture extends LitElement {\n private static stylesInjected = false;\n\n // Use Light DOM for Tailwind compatibility\n protected createRenderRoot() {\n ProfilePicture.injectStylesOnce();\n return this;\n }\n\n private static injectStylesOnce() {\n if (ProfilePicture.stylesInjected || typeof document === \"undefined\") {\n return;\n }\n const style = document.createElement(\"style\");\n style.textContent = componentStyles;\n document.head.appendChild(style);\n ProfilePicture.stylesInjected = true;\n }\n\n // ─── Core Properties ────────────────────────────────────────────────────────\n @property({ type: String }) src = \"\";\n @property({ type: String }) alt = \"\";\n\n // ─── Sizing ─────────────────────────────────────────────────────────────────\n @property({ type: String }) size: Size | string = DEFAULTS.size;\n\n // ─── Visual Variant ─────────────────────────────────────────────────────────\n @property({ type: String }) variant: Variant = DEFAULTS.variant;\n\n // ─── Shadow ─────────────────────────────────────────────────────────────────\n @property({ type: String }) shadow: ShadowPreset = DEFAULTS.shadow;\n\n // ─── Border ─────────────────────────────────────────────────────────────────\n @property({ type: Boolean }) border = false;\n @property({ type: Number, attribute: \"border-width\" }) borderWidth:\n | 1\n | 2\n | 3\n | 4 = DEFAULTS.borderWidth;\n @property({ type: String, attribute: \"border-color\" }) borderColor: string =\n DEFAULTS.borderColor;\n\n // ─── Background ─────────────────────────────────────────────────────────────\n @property({ type: String, attribute: \"bg-color\" }) bgColor?: string;\n @property({ type: String, attribute: \"bg-gradient\" }) bgGradient?: string;\n\n // ─── Ring Effect (Instagram-style) ──────────────────────────────────────────\n @property({ type: Object, attribute: false }) ring?: RingConfig;\n\n // ─── Presence Indicator ─────────────────────────────────────────────────────\n @property({ type: Object, attribute: false }) presence?: PresenceConfig;\n\n // ─── Glow Effect ────────────────────────────────────────────────────────────\n @property({ type: Object, attribute: false }) glow?: GlowConfig;\n\n // ─── Ribbon ─────────────────────────────────────────────────────────────────\n @property({ type: Object, attribute: false }) ribbon?: RibbonConfig;\n\n // ─── Badge ──────────────────────────────────────────────────────────────────\n @property({ type: Object, attribute: false }) badge?: BadgeConfig;\n\n // ─── Loading & Performance ──────────────────────────────────────────────────\n @property({ type: String }) loading: LoadingStrategy = DEFAULTS.loading;\n @property({ type: String }) placeholder: PlaceholderType =\n DEFAULTS.placeholder;\n @property({ type: String, attribute: \"placeholder-color\" })\n placeholderColor: string = DEFAULTS.placeholderColor;\n\n // ─── Fallback ───────────────────────────────────────────────────────────────\n @property({ type: String }) fallback?: string;\n\n // ─── Interaction ────────────────────────────────────────────────────────────\n @property({ type: Object, attribute: false }) interactive?: InteractionConfig;\n\n // ─── Internal State ─────────────────────────────────────────────────────────\n @state() private isLoaded = false;\n @state() private hasError = false;\n private previousSrc = \"\";\n\n private get pixelSize(): number {\n const sizeValue = this.size as Size | number;\n return typeof sizeValue === \"number\"\n ? sizeValue\n : (SIZE_MAP[sizeValue as Size] ?? SIZE_MAP[DEFAULTS.size]);\n }\n\n protected willUpdate(changedProperties: Map<string, unknown>): void {\n if (changedProperties.has(\"src\") && this.src !== this.previousSrc) {\n this.isLoaded = false;\n this.hasError = false;\n this.previousSrc = this.src;\n }\n }\n\n private handleLoad() {\n this.isLoaded = true;\n this.dispatchEvent(\n new CustomEvent(\"load\", { bubbles: true, composed: true })\n );\n }\n\n private handleError() {\n this.hasError = true;\n this.isLoaded = true;\n this.dispatchEvent(\n new CustomEvent(\"error\", { bubbles: true, composed: true })\n );\n }\n\n private getContainerStyles() {\n const bg = getBackgroundStyles(this.bgColor, this.bgGradient);\n const borderStyles = this.border\n ? getBorderClasses(this.borderWidth, this.borderColor)\n : null;\n const shadowStyles = getShadowStyles(this.shadow);\n\n // Handle glow effect\n let glowStyles: Record<string, string> = {};\n if (this.glow) {\n const glowColor = this.glow.color ?? this.borderColor ?? \"#6366f1\";\n glowStyles = {\n \"--pp-glow-color\": glowColor,\n boxShadow: getGlowShadow(glowColor, this.glow.intensity ?? 0.3),\n };\n }\n\n const isInteractive =\n this.interactive?.hoverable || this.interactive?.pressable;\n\n return {\n classes: cn(\n \"pp-container\",\n getVariantClasses(this.variant),\n bg.className,\n borderStyles?.className,\n isInteractive && \"pp-interactive\",\n this.glow?.animate && \"pp-glow\"\n ),\n styles: {\n width: `${this.pixelSize}px`,\n height: `${this.pixelSize}px`,\n borderRadius: RADIUS_MAP[this.variant],\n ...bg.style,\n ...borderStyles?.style,\n ...shadowStyles,\n ...glowStyles,\n cursor:\n this.interactive?.cursor ?? (isInteractive ? \"pointer\" : \"default\"),\n },\n };\n }\n\n private renderPlaceholder() {\n if (this.isLoaded || this.placeholder === \"none\") {\n return nothing;\n }\n\n const placeholderClass = {\n shimmer: \"pp-shimmer\",\n pulse: \"pp-pulse\",\n skeleton: \"pp-skeleton\",\n blur: \"\",\n none: \"\",\n }[this.placeholder];\n\n return html`\n ${this.placeholder === \"shimmer\" ? html`<style>${shimmerStyles}</style>` : nothing}\n <div\n class=${cn(\"np:absolute np:inset-0\", placeholderClass)}\n style=${styleMap({\n backgroundColor: this.placeholderColor,\n borderRadius: \"inherit\",\n })}>\n </div>\n `;\n }\n\n private renderFallback() {\n // Use custom fallback text if provided\n if (this.fallback) {\n return html`\n <span\n class=\"pp-fallback\"\n style=${styleMap({ fontSize: `${getInitialsFontSize(this.pixelSize)}px` })}>\n ${this.fallback}\n </span>\n `;\n }\n\n // Generate initials from alt text\n if (this.alt) {\n const gradient = generateAvatarGradient(this.alt);\n return html`\n <div\n class=\"pp-fallback np:absolute np:inset-0\"\n style=${styleMap({\n background: this.bgColor ?? gradient,\n fontSize: `${getInitialsFontSize(this.pixelSize)}px`,\n })}>\n ${getInitials(this.alt)}\n </div>\n `;\n }\n\n // Default user icon\n const iconSize = this.pixelSize * 0.5;\n return html`\n <svg\n class=\"pp-fallback-icon\"\n style=\"width: ${iconSize}px; height: ${iconSize}px;\"\n fill=\"currentColor\"\n viewBox=\"0 0 24 24\">\n <path d=\"M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z\" />\n </svg>\n `;\n }\n\n private renderImage() {\n if (this.hasError || !this.src) {\n return this.renderFallback();\n }\n\n return html`\n <img\n src=${this.src}\n alt=${this.alt}\n loading=${this.loading}\n decoding=\"async\"\n @load=${this.handleLoad}\n @error=${this.handleError}\n class=${cn(\"pp-image\", this.isLoaded ? \"pp-image-loaded\" : \"pp-image-loading\")}\n draggable=\"false\" />\n `;\n }\n\n private renderRing() {\n if (!this.ring?.show) {\n return nothing;\n }\n\n const ringWidth = this.ring.width ?? 3;\n const ringGap = this.ring.gap ?? 3;\n const totalOffset = ringWidth + ringGap;\n\n let ringColor: string;\n if (this.ring.gradient && this.ring.gradient.length > 0) {\n ringColor = createConicGradient(this.ring.gradient);\n } else {\n ringColor =\n this.ring.color ??\n \"linear-gradient(45deg, #f09433, #e6683c, #dc2743, #cc2366, #bc1888)\";\n }\n\n return html`\n <div\n class=${cn(\"pp-ring\", this.ring.animate && \"pp-ring-animated\")}\n style=${styleMap({\n inset: `-${totalOffset}px`,\n padding: `${ringWidth}px`,\n background: ringColor,\n borderRadius: RADIUS_MAP[this.variant],\n })}>\n </div>\n `;\n }\n\n private renderPresence() {\n if (!this.presence) {\n return nothing;\n }\n\n const thickness = this.presence.thickness ?? 2;\n const size = getPresenceSize(this.pixelSize, thickness);\n const color = PRESENCE_COLORS[this.presence.status];\n\n // Position offset based on avatar size\n const offset = Math.max(0, this.pixelSize * 0.02);\n\n return html`\n <div\n class=${cn(\"pp-presence\", this.presence.animate && \"pp-presence-animated\")}\n style=${styleMap({\n width: `${size}px`,\n height: `${size}px`,\n backgroundColor: color,\n bottom: `${offset}px`,\n right: `${offset}px`,\n color,\n })}\n title=${this.presence.status}>\n </div>\n `;\n }\n\n private renderBadge() {\n if (!this.badge) {\n return nothing;\n }\n\n const position = this.badge.position ?? \"bottom-right\";\n const hasContent = this.badge.content !== undefined;\n const { size: badgeSize, fontSize } = getBadgeSize(\n this.pixelSize,\n hasContent\n );\n\n const bgColor = this.badge.bgColor ?? \"#22c55e\";\n const textColor = this.badge.color ?? \"#ffffff\";\n\n // Format content (99+ for large numbers)\n const content =\n hasContent && this.badge.content !== undefined\n ? formatBadgeContent(this.badge.content, this.badge.max)\n : null;\n\n const positionStyles: Record<Position, Record<string, string>> = {\n \"top-left\": { top: \"-4px\", left: \"-4px\" },\n \"top-right\": { top: \"-4px\", right: \"-4px\" },\n \"bottom-left\": { bottom: \"-4px\", left: \"-4px\" },\n \"bottom-right\": { bottom: \"-4px\", right: \"-4px\" },\n };\n\n return html`\n <div\n class=${cn(\n \"pp-badge\",\n this.badge.pulse && \"pp-badge-pulse\",\n this.badge.glow && \"pp-badge-glow\"\n )}\n style=${styleMap({\n width: hasContent ? \"auto\" : `${badgeSize}px`,\n minWidth: `${badgeSize}px`,\n height: `${badgeSize}px`,\n padding: hasContent ? \"0 6px\" : \"0\",\n fontSize: `${fontSize}px`,\n backgroundColor: bgColor,\n color: textColor,\n \"--pp-badge-glow-color\": bgColor,\n ...positionStyles[position],\n })}>\n ${content ?? nothing}\n </div>\n `;\n }\n\n private renderRibbon() {\n if (!this.ribbon) {\n return nothing;\n }\n\n const position = this.ribbon.position ?? \"top-right\";\n const ribbonBg = this.ribbon.bgColor ?? \"#ef4444\";\n const ribbonColor = this.ribbon.color ?? \"#ffffff\";\n\n const bgStyle = isHexColor(ribbonBg)\n ? { backgroundColor: ribbonBg }\n : { background: ribbonBg };\n const colorStyle = { color: ribbonColor };\n\n // Calculate ribbon dimensions based on avatar size\n const ribbonWidth = this.pixelSize * 0.9;\n const ribbonHeight = this.pixelSize * 0.4;\n const fontSize = Math.max(8, this.pixelSize * 0.11);\n\n return html`\n <div\n class=${cn(\"pp-ribbon-container\", getPositionClasses(position))}\n style=${styleMap({\n width: `${ribbonWidth}px`,\n height: `${ribbonHeight}px`,\n })}>\n <div\n class=${cn(\n \"pp-ribbon np:origin-center np:transform\",\n getRibbonRotation(position)\n )}\n style=${styleMap({\n fontSize: `${fontSize}px`,\n padding: `${fontSize * 0.3}px 0`,\n ...bgStyle,\n ...colorStyle,\n })}>\n ${this.ribbon.icon ? html`<span style=\"margin-right: 2px\">${this.ribbon.icon}</span>` : nothing}\n ${this.ribbon.text}\n </div>\n </div>\n `;\n }\n\n render() {\n const container = this.getContainerStyles();\n\n const tabIndex =\n this.interactive?.focusable || this.interactive?.pressable\n ? 0\n : undefined;\n\n return html`\n <div\n class=${container.classes}\n style=${styleMap(container.styles)}\n tabindex=${tabIndex ?? nothing}\n role=${this.interactive?.pressable ? \"button\" : nothing}\n aria-label=${this.alt || nothing}\n data-profile-picture>\n\n <!-- Ring Effect (behind everything) -->\n ${this.renderRing()}\n\n <!-- Inner container for image clipping -->\n <div\n class=\"pp-inner\"\n style=${styleMap({\n borderRadius: RADIUS_MAP[this.variant],\n })}>\n <!-- Placeholder -->\n ${this.renderPlaceholder()}\n\n <!-- Main Image or Fallback -->\n ${this.renderImage()}\n </div>\n\n <!-- Ribbon -->\n ${this.renderRibbon()}\n\n <!-- Badge -->\n ${this.renderBadge()}\n\n <!-- Presence Indicator -->\n ${this.renderPresence()}\n </div>\n `;\n }\n}\n\n// Export types for TypeScript users\nexport type {\n BadgeConfig,\n GlowConfig,\n InteractionConfig,\n LoadingStrategy,\n PlaceholderType,\n Position,\n PresenceConfig,\n PresenceStatus,\n RibbonConfig,\n RingConfig,\n ShadowPreset,\n Size,\n Variant,\n} from \"./types\";\n\n// Ensure component is registered\ndeclare global {\n interface HTMLElementTagNameMap {\n \"profile-picture\": ProfilePicture;\n }\n}\n\nexport default ProfilePicture;\n","/**\n * ProfilePictureGroup Web Component\n * Apple-inspired stacked avatar group with tooltips, counter, and dropdown\n *\n * A lightweight, framework-agnostic component for displaying\n * multiple profile pictures in a visually appealing stacked layout.\n */\n\nimport { html, LitElement, nothing } from \"lit\";\nimport { customElement, property, state } from \"lit/decorators.js\";\nimport { styleMap } from \"lit/directives/style-map.js\";\nimport { groupStyles } from \"./styles\";\nimport type {\n DropdownConfig,\n GroupUserData,\n Size,\n StackDirection,\n TooltipConfig,\n TooltipPosition,\n} from \"./types\";\nimport { GROUP_DEFAULTS } from \"./types\";\nimport {\n calculateAvatarCounts,\n calculateGroupWidth,\n calculateStackPosition,\n calculateStackZIndex,\n cn,\n formatCounterText,\n generateAvatarGradient,\n getGroupAvatarSize,\n getInitials,\n} from \"./utils\";\n\n// Inject group styles once\nlet groupStylesInjected = false;\nfunction injectGroupStyles() {\n if (groupStylesInjected || typeof document === \"undefined\") {\n return;\n }\n const style = document.createElement(\"style\");\n style.textContent = groupStyles;\n document.head.appendChild(style);\n groupStylesInjected = true;\n}\n\n@customElement(\"profile-picture-group\")\nexport class ProfilePictureGroup extends LitElement {\n // Use Light DOM for Tailwind compatibility\n protected createRenderRoot() {\n injectGroupStyles();\n return this;\n }\n\n // ─── Core Properties ────────────────────────────────────────────────────────\n @property({ type: Number }) max = GROUP_DEFAULTS.max;\n @property({ type: String }) direction: StackDirection =\n GROUP_DEFAULTS.direction;\n @property({ type: Number }) overlap = GROUP_DEFAULTS.overlap;\n @property({ type: String }) size: Size | string = GROUP_DEFAULTS.size;\n @property({ type: Number }) spacing?: number;\n @property({ type: Object }) tooltip?: TooltipConfig;\n @property({ type: Object }) dropdown?: DropdownConfig;\n @property({ type: Boolean, attribute: \"show-add-button\" }) showAddButton =\n false;\n @property({ type: String, attribute: \"add-button-label\" }) addButtonLabel =\n \"Add user\";\n @property({ type: Boolean }) animated = GROUP_DEFAULTS.animated;\n\n // ─── Internal State ─────────────────────────────────────────────────────────\n @state() private users: GroupUserData[] = [];\n @state() private dropdownOpen = false;\n @state() private tooltipData: {\n user: GroupUserData;\n rect: DOMRect;\n } | null = null;\n private tooltipTimeout: number | null = null;\n private slotObserver: MutationObserver | null = null;\n\n private get pixelSize(): number {\n return getGroupAvatarSize(this.size as Size | number);\n }\n\n private get tooltipEnabled(): boolean {\n return this.tooltip?.enabled !== false;\n }\n\n private get tooltipPosition(): TooltipPosition {\n return this.tooltip?.position ?? \"top\";\n }\n\n private get tooltipDelay(): number {\n return this.tooltip?.delay ?? GROUP_DEFAULTS.tooltipDelay;\n }\n\n private get dropdownMaxHeight(): number {\n return this.dropdown?.maxHeight ?? GROUP_DEFAULTS.dropdownMaxHeight;\n }\n\n private get showPresence(): boolean {\n return this.dropdown?.showPresence !== false;\n }\n\n private get dropdownPosition(): \"top\" | \"bottom\" {\n return this.dropdown?.position ?? \"bottom\";\n }\n\n // ─── Lifecycle ──────────────────────────────────────────────────────────────\n\n connectedCallback() {\n super.connectedCallback();\n this.updateUsers();\n this.setupSlotObserver();\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n this.slotObserver?.disconnect();\n this.clearTooltipTimeout();\n }\n\n private setupSlotObserver() {\n // Watch for child element changes\n this.slotObserver = new MutationObserver(() => {\n this.updateUsers();\n });\n\n this.slotObserver.observe(this, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: [\n \"src\",\n \"alt\",\n \"data-user-id\",\n \"data-status\",\n \"variant\",\n \"shadow\",\n \"border\",\n \"border-width\",\n \"border-color\",\n \"bg-color\",\n \"bg-gradient\",\n ],\n });\n }\n\n private updateUsers() {\n // Only select direct children profile-picture elements (slotted content),\n // not the ones we render inside the ppg-container\n const children = Array.from(this.children).filter(\n (child) =>\n child.tagName.toLowerCase() === \"profile-picture\" &&\n child.getAttribute(\"slot\") !== \"internal\"\n );\n\n this.users = children.map((el, index) => {\n // Extract border-width as number\n const borderWidthAttr = el.getAttribute(\"border-width\");\n const borderWidth = borderWidthAttr\n ? (Number.parseInt(borderWidthAttr, 10) as 1 | 2 | 3 | 4)\n : undefined;\n\n return {\n // Core data\n id: el.getAttribute(\"data-user-id\") ?? undefined,\n name: el.getAttribute(\"alt\") ?? `User ${index + 1}`,\n src: el.getAttribute(\"src\") ?? undefined,\n status:\n (el.getAttribute(\"data-status\") as GroupUserData[\"status\"]) ??\n undefined,\n element: el as HTMLElement,\n index,\n\n // Profile picture props (passed through from slotted elements)\n variant:\n (el.getAttribute(\"variant\") as GroupUserData[\"variant\"]) ?? undefined,\n shadow:\n (el.getAttribute(\"shadow\") as GroupUserData[\"shadow\"]) ?? undefined,\n border: el.hasAttribute(\"border\"),\n borderWidth,\n borderColor: el.getAttribute(\"border-color\") ?? undefined,\n bgColor: el.getAttribute(\"bg-color\") ?? undefined,\n bgGradient: el.getAttribute(\"bg-gradient\") ?? undefined,\n };\n });\n\n // Hide ALL slotted elements since we're rendering our own\n for (const user of this.users) {\n if (user.element) {\n user.element.style.display = \"none\";\n }\n }\n }\n\n // ─── Event Handlers ─────────────────────────────────────────────────────────\n\n private handleAvatarClick(user: GroupUserData) {\n this.dispatchEvent(\n new CustomEvent(\"avatar-click\", {\n detail: { user },\n bubbles: true,\n composed: true,\n })\n );\n }\n\n private handleAvatarHover(user: GroupUserData, event: MouseEvent) {\n if (!this.tooltipEnabled) {\n return;\n }\n\n this.clearTooltipTimeout();\n const target = event.currentTarget as HTMLElement;\n\n this.tooltipTimeout = window.setTimeout(() => {\n this.tooltipData = {\n user,\n rect: target.getBoundingClientRect(),\n };\n }, this.tooltipDelay);\n\n this.dispatchEvent(\n new CustomEvent(\"avatar-hover\", {\n detail: { user },\n bubbles: true,\n composed: true,\n })\n );\n }\n\n private handleAvatarLeave() {\n this.clearTooltipTimeout();\n this.tooltipData = null;\n }\n\n private clearTooltipTimeout() {\n if (this.tooltipTimeout) {\n window.clearTimeout(this.tooltipTimeout);\n this.tooltipTimeout = null;\n }\n }\n\n private handleCounterClick(hiddenUsers: GroupUserData[]) {\n this.dropdownOpen = !this.dropdownOpen;\n\n this.dispatchEvent(\n new CustomEvent(\"counter-click\", {\n detail: { hiddenUsers, open: this.dropdownOpen },\n bubbles: true,\n composed: true,\n })\n );\n }\n\n private readonly handleBackdropClick = () => {\n this.dropdownOpen = false;\n };\n\n private handleDropdownItemClick(user: GroupUserData) {\n this.dropdownOpen = false;\n\n this.dispatchEvent(\n new CustomEvent(\"dropdown-item-click\", {\n detail: { user },\n bubbles: true,\n composed: true,\n })\n );\n }\n\n private handleAddClick() {\n this.dispatchEvent(\n new CustomEvent(\"add-click\", {\n bubbles: true,\n composed: true,\n })\n );\n }\n\n private handleKeyDown(event: KeyboardEvent, handler: () => void) {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n handler();\n }\n }\n\n // ─── Rendering ──────────────────────────────────────────────────────────────\n\n private renderAvatar(user: GroupUserData, index: number, total: number) {\n const position = calculateStackPosition(\n index,\n this.pixelSize,\n this.overlap,\n this.direction,\n this.spacing\n );\n const zIndex = calculateStackZIndex(index, total, this.direction);\n\n // Use user's variant or default to circle for groups\n const variant = user.variant ?? \"circle\";\n // Use user's shadow or default to none for cleaner stacking\n const shadow = user.shadow ?? \"none\";\n\n return html`\n <div\n class=\"ppg-avatar-wrapper\"\n style=${styleMap({\n left: `${position}px`,\n zIndex: String(zIndex),\n width: `${this.pixelSize}px`,\n height: `${this.pixelSize}px`,\n })}\n tabindex=\"0\"\n role=\"button\"\n aria-label=${user.name}\n @click=${() => this.handleAvatarClick(user)}\n @mouseenter=${(e: MouseEvent) => this.handleAvatarHover(user, e)}\n @mouseleave=${this.handleAvatarLeave}\n @keydown=${(e: KeyboardEvent) =>\n this.handleKeyDown(e, () => this.handleAvatarClick(user))}\n >\n ${this.renderProfilePicture(user, variant, shadow)}\n </div>\n `;\n }\n\n private renderProfilePicture(\n user: GroupUserData,\n variant: string,\n shadow: string\n ) {\n // Build the profile-picture element with only defined attributes\n // This avoids passing empty strings which might override defaults\n // Default to white background when wrapped in group\n return html`\n <profile-picture\n .src=${user.src ?? \"\"}\n .alt=${user.name}\n .size=${this.pixelSize}\n .variant=${variant}\n .shadow=${shadow}\n ?border=${user.border}\n .borderWidth=${user.border ? (user.borderWidth ?? 2) : 2}\n .borderColor=${user.border ? (user.borderColor ?? \"#ffffff\") : \"#ffffff\"}\n .bgColor=${user.bgGradient ? undefined : (user.bgColor ?? \"#ffffff\")}\n .bgGradient=${user.bgGradient ?? undefined}\n data-user-id=${user.id ?? \"\"}\n data-status=${user.status ?? \"\"}\n ></profile-picture>\n `;\n }\n\n private renderCounter(count: number, position: number) {\n return html`\n <button\n class=\"ppg-counter\"\n style=${styleMap({\n left: `${position}px`,\n width: `${this.pixelSize}px`,\n height: `${this.pixelSize}px`,\n zIndex: \"1\",\n })}\n aria-label=${`${count} more users`}\n aria-expanded=${this.dropdownOpen}\n aria-haspopup=\"true\"\n @click=${() => this.handleCounterClick(this.users.slice(-count))}\n >\n ${formatCounterText(count)}\n </button>\n `;\n }\n\n private renderAddButton(position: number) {\n const iconSize = Math.round(this.pixelSize * 0.4);\n\n return html`\n <button\n class=\"ppg-add-button\"\n style=${styleMap({\n left: `${position}px`,\n width: `${this.pixelSize}px`,\n height: `${this.pixelSize}px`,\n zIndex: \"1\",\n })}\n aria-label=${this.addButtonLabel}\n @click=${this.handleAddClick}\n >\n <svg\n class=\"ppg-add-icon\"\n width=${iconSize}\n height=${iconSize}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"></line>\n <line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"></line>\n </svg>\n </button>\n `;\n }\n\n private renderTooltip() {\n if (!this.tooltipData) {\n return nothing;\n }\n\n const { user, rect } = this.tooltipData;\n const gap = 8;\n\n let top: number;\n let left: number;\n\n // Simple positioning - we refine in CSS\n switch (this.tooltipPosition) {\n case \"bottom\":\n top = rect.bottom + gap;\n left = rect.left + rect.width / 2;\n break;\n default: // top\n top = rect.top - gap;\n left = rect.left + rect.width / 2;\n }\n\n return html`\n <div\n class=\"ppg-tooltip\"\n style=${styleMap({\n top: this.tooltipPosition === \"top\" ? \"auto\" : `${top}px`,\n bottom:\n this.tooltipPosition === \"top\"\n ? `${window.innerHeight - rect.top + gap}px`\n : \"auto\",\n left: `${left}px`,\n transform: \"translateX(-50%)\",\n })}\n data-position=${this.tooltipPosition}\n role=\"tooltip\"\n >\n ${user.name}\n </div>\n `;\n }\n\n private renderDropdown(hiddenUsers: GroupUserData[]) {\n if (!this.dropdownOpen) {\n return nothing;\n }\n\n return html`\n <div\n class=\"ppg-backdrop\"\n @click=${this.handleBackdropClick}\n aria-hidden=\"true\"\n ></div>\n <div\n class=\"ppg-dropdown\"\n data-position=${this.dropdownPosition}\n role=\"menu\"\n aria-label=\"Hidden users\"\n >\n <div class=\"ppg-dropdown-header\">\n ${hiddenUsers.length} more\n </div>\n <div\n class=\"ppg-dropdown-list\"\n style=${styleMap({\n maxHeight: `${this.dropdownMaxHeight}px`,\n })}\n >\n ${hiddenUsers.map((user) => this.renderDropdownItem(user))}\n </div>\n </div>\n `;\n }\n\n private renderDropdownItem(user: GroupUserData) {\n const gradient = generateAvatarGradient(user.name);\n\n return html`\n <div\n class=\"ppg-dropdown-item\"\n role=\"menuitem\"\n tabindex=\"0\"\n @click=${() => this.handleDropdownItemClick(user)}\n @keydown=${(e: KeyboardEvent) =>\n this.handleKeyDown(e, () => this.handleDropdownItemClick(user))}\n >\n ${\n user.src\n ? html`<img\n class=\"ppg-dropdown-avatar\"\n src=${user.src}\n alt=${user.name}\n />`\n : html`<div\n class=\"ppg-dropdown-avatar-fallback\"\n style=${styleMap({ background: gradient })}\n >\n ${getInitials(user.name)}\n </div>`\n }\n <div class=\"ppg-dropdown-info\">\n <div class=\"ppg-dropdown-name\">${user.name}</div>\n ${\n this.showPresence && user.status\n ? html`\n <div class=\"ppg-dropdown-status\">\n <span\n class=\"ppg-dropdown-presence\"\n data-status=${user.status}\n ></span>\n ${this.formatStatus(user.status)}\n </div>\n `\n : nothing\n }\n </div>\n </div>\n `;\n }\n\n private formatStatus(status: string): string {\n const labels: Record<string, string> = {\n online: \"Online\",\n away: \"Away\",\n busy: \"Busy\",\n offline: \"Offline\",\n dnd: \"Do not disturb\",\n };\n return labels[status] ?? status;\n }\n\n render() {\n const { visible, hidden, showCounter } = calculateAvatarCounts(\n this.users.length,\n this.max,\n this.showAddButton\n );\n\n // Determine which users to show\n const visibleUsers =\n this.direction === \"ltr\"\n ? this.users.slice(0, visible)\n : this.users.slice(0, visible).reverse();\n\n const hiddenUsers = this.users.slice(visible);\n\n // Calculate element count for width\n let elementCount = visible;\n if (showCounter) {\n elementCount++;\n }\n if (this.showAddButton) {\n elementCount++;\n }\n\n const containerWidth = calculateGroupWidth(\n elementCount,\n this.pixelSize,\n this.overlap,\n this.spacing\n );\n\n // Calculate positions for counter and add button\n const counterPosition = showCounter\n ? calculateStackPosition(\n visible,\n this.pixelSize,\n this.overlap,\n this.direction,\n this.spacing\n )\n : 0;\n\n const addButtonPosition = calculateStackPosition(\n visible + (showCounter ? 1 : 0),\n this.pixelSize,\n this.overlap,\n this.direction,\n this.spacing\n );\n\n return html`\n <div\n class=${cn(\"ppg-container\", this.animated && \"ppg-animated\")}\n style=${styleMap({\n width: `${containerWidth}px`,\n height: `${this.pixelSize}px`,\n })}\n role=\"group\"\n aria-label=\"User avatars\"\n >\n <!-- Hidden slot for original children -->\n <slot style=\"display: none;\"></slot>\n\n <!-- Visible avatars -->\n ${visibleUsers.map((user, index) =>\n this.renderAvatar(user, index, visible)\n )}\n\n <!-- Counter -->\n ${showCounter ? this.renderCounter(hidden, counterPosition) : nothing}\n\n <!-- Add button -->\n ${this.showAddButton ? this.renderAddButton(addButtonPosition) : nothing}\n\n <!-- Tooltip -->\n ${this.renderTooltip()}\n\n <!-- Dropdown -->\n ${showCounter ? this.renderDropdown(hiddenUsers) : nothing}\n </div>\n `;\n }\n}\n\n// Export types for TypeScript users\nexport type {\n DropdownConfig,\n GroupUserData,\n ProfilePictureGroupProps,\n StackDirection,\n TooltipConfig,\n TooltipPosition,\n} from \"./types\";\n\n// Ensure component is registered\ndeclare global {\n interface HTMLElementTagNameMap {\n \"profile-picture-group\": ProfilePictureGroup;\n }\n}\n\nexport default ProfilePictureGroup;\n","/**\n * React wrapper for ProfilePictureGroup Web Component\n *\n * Provides a type-safe React interface for the ProfilePictureGroup web component.\n *\n * @example\n * ```tsx\n * import { ProfilePictureGroup, ProfilePicture } from '@grasco/profile-picture';\n *\n * function App() {\n * return (\n * <ProfilePictureGroup\n * max={4}\n * direction=\"ltr\"\n * overlap={0.3}\n * size=\"md\"\n * showAddButton\n * onAvatarClick={(user) => console.log('Clicked:', user)}\n * onAddClick={() => console.log('Add clicked')}\n * >\n * <ProfilePicture src=\"avatar1.jpg\" alt=\"John Doe\" data-user-id=\"1\" />\n * <ProfilePicture src=\"avatar2.jpg\" alt=\"Jane Smith\" data-user-id=\"2\" />\n * <ProfilePicture src=\"avatar3.jpg\" alt=\"Bob Wilson\" data-user-id=\"3\" />\n * </ProfilePictureGroup>\n * );\n * }\n * ```\n */\n\nimport React, { useCallback, useEffect, useRef } from \"react\";\nimport type {\n DropdownConfig,\n GroupUserData,\n Size,\n StackDirection,\n TooltipConfig,\n} from \"../../core/types\";\n\n// Import and register the web component\nimport \"../../core/ProfilePictureGroup\";\n\nexport interface ProfilePictureGroupProps {\n /** Maximum visible avatars before showing counter (default: 4) */\n max?: number;\n /** Stack direction - ltr shows first on left (default: 'ltr') */\n direction?: StackDirection;\n /** Overlap amount as percentage 0-1 (default: 0.3) */\n overlap?: number;\n /** Avatar size - inherited by children (default: 'md') */\n size?: Size | number;\n /** Spacing between avatars in px (overrides overlap calculation) */\n spacing?: number;\n /** Tooltip configuration */\n tooltip?: TooltipConfig;\n /** Dropdown configuration for overflow users */\n dropdown?: DropdownConfig;\n /** Show add button (default: false) */\n showAddButton?: boolean;\n /** Add button label for accessibility */\n addButtonLabel?: string;\n /** Enable hover lift animation (default: true) */\n animated?: boolean;\n\n // Event callbacks\n /** Called when an avatar is clicked */\n onAvatarClick?: (user: GroupUserData) => void;\n /** Called when hovering over an avatar */\n onAvatarHover?: (user: GroupUserData) => void;\n /** Called when the counter is clicked */\n onCounterClick?: (hiddenUsers: GroupUserData[], open: boolean) => void;\n /** Called when a dropdown item is clicked */\n onDropdownItemClick?: (user: GroupUserData) => void;\n /** Called when the add button is clicked */\n onAddClick?: () => void;\n\n // Passthrough\n className?: string;\n style?: React.CSSProperties;\n children?: React.ReactNode;\n}\n\n/**\n * ProfilePictureGroup React Component\n *\n * Type-safe wrapper around the profile-picture-group web component\n */\nexport const ProfilePictureGroup = React.forwardRef<\n HTMLElement,\n ProfilePictureGroupProps\n>(\n (\n {\n max,\n direction,\n overlap,\n size,\n spacing,\n tooltip,\n dropdown,\n showAddButton,\n addButtonLabel,\n animated,\n onAvatarClick,\n onAvatarHover,\n onCounterClick,\n onDropdownItemClick,\n onAddClick,\n className,\n style,\n children,\n },\n ref\n ) => {\n const elementRef = useRef<HTMLElement>(null);\n\n // Handle events\n const handleAvatarClick = useCallback(\n (event: Event) => {\n const customEvent = event as CustomEvent<{ user: GroupUserData }>;\n onAvatarClick?.(customEvent.detail.user);\n },\n [onAvatarClick]\n );\n\n const handleAvatarHover = useCallback(\n (event: Event) => {\n const customEvent = event as CustomEvent<{ user: GroupUserData }>;\n onAvatarHover?.(customEvent.detail.user);\n },\n [onAvatarHover]\n );\n\n const handleCounterClick = useCallback(\n (event: Event) => {\n const customEvent = event as CustomEvent<{\n hiddenUsers: GroupUserData[];\n open: boolean;\n }>;\n onCounterClick?.(\n customEvent.detail.hiddenUsers,\n customEvent.detail.open\n );\n },\n [onCounterClick]\n );\n\n const handleDropdownItemClick = useCallback(\n (event: Event) => {\n const customEvent = event as CustomEvent<{ user: GroupUserData }>;\n onDropdownItemClick?.(customEvent.detail.user);\n },\n [onDropdownItemClick]\n );\n\n const handleAddClick = useCallback(() => {\n onAddClick?.();\n }, [onAddClick]);\n\n // Set up event listeners\n useEffect(() => {\n const element = elementRef.current;\n if (!element) {\n return;\n }\n\n element.addEventListener(\"avatar-click\", handleAvatarClick);\n element.addEventListener(\"avatar-hover\", handleAvatarHover);\n element.addEventListener(\"counter-click\", handleCounterClick);\n element.addEventListener(\"dropdown-item-click\", handleDropdownItemClick);\n element.addEventListener(\"add-click\", handleAddClick);\n\n return () => {\n element.removeEventListener(\"avatar-click\", handleAvatarClick);\n element.removeEventListener(\"avatar-hover\", handleAvatarHover);\n element.removeEventListener(\"counter-click\", handleCounterClick);\n element.removeEventListener(\n \"dropdown-item-click\",\n handleDropdownItemClick\n );\n element.removeEventListener(\"add-click\", handleAddClick);\n };\n }, [\n handleAvatarClick,\n handleAvatarHover,\n handleCounterClick,\n handleDropdownItemClick,\n handleAddClick,\n ]);\n\n // Sync ref\n useEffect(() => {\n if (typeof ref === \"function\") {\n ref(elementRef.current);\n } else if (ref) {\n ref.current = elementRef.current;\n }\n }, [ref]);\n\n return React.createElement(\n \"profile-picture-group\",\n {\n ref: elementRef,\n max,\n direction,\n overlap,\n size,\n spacing,\n tooltip,\n dropdown,\n \"show-add-button\": showAddButton || undefined,\n \"add-button-label\": addButtonLabel,\n animated,\n class: className,\n style,\n },\n children\n );\n }\n);\n\nProfilePictureGroup.displayName = \"ProfilePictureGroup\";\n\n// Re-export types\nexport type {\n DropdownConfig,\n GroupUserData,\n Size,\n StackDirection,\n TooltipConfig,\n};\n\nexport default ProfilePictureGroup;\n","/**\n * React wrapper for ProfilePicture Web Component\n *\n * Provides a type-safe React interface for the ProfilePicture web component.\n *\n * @example\n * ```tsx\n * import { ProfilePicture } from '@grasco/profile-picture';\n *\n * function App() {\n * return (\n * <ProfilePicture\n * src=\"https://example.com/avatar.png\"\n * alt=\"John Doe\"\n * size=\"lg\"\n * variant=\"circle\"\n * border\n * borderColor=\"white\"\n * bgColor=\"bg-gradient-to-br from-purple-500 to-pink-500\"\n * ribbon={{ text: 'PRO', position: 'top-right', bgColor: 'bg-amber-500' }}\n * badge={{ content: '3', position: 'bottom-right', pulse: true }}\n * onLoad={() => console.log('loaded')}\n * onError={() => console.error('failed')}\n * />\n * );\n * }\n * ```\n */\n\nimport React from \"react\";\nimport type {\n BadgeConfig,\n LoadingStrategy,\n PlaceholderType,\n RibbonConfig,\n Size,\n Variant,\n} from \"../../core/ProfilePicture\";\n\n// Import and register the web component\nimport \"../../core/ProfilePicture\";\n\nexport interface ProfilePictureProps {\n // Core\n src: string;\n alt?: string;\n\n // Sizing\n size?: Size | number;\n\n // Visual Variant\n variant?: Variant;\n\n // Border\n border?: boolean;\n borderWidth?: 1 | 2 | 3 | 4;\n borderColor?: string;\n\n // Background\n bgColor?: string;\n bgGradient?: string;\n\n // Ribbon\n ribbon?: RibbonConfig;\n\n // Badge\n badge?: BadgeConfig;\n\n // Loading & Performance\n loading?: LoadingStrategy;\n placeholder?: PlaceholderType;\n placeholderColor?: string;\n\n // Fallback\n fallback?: string;\n\n // Events\n onLoad?: () => void;\n onError?: () => void;\n\n // Passthrough\n className?: string;\n style?: React.CSSProperties;\n}\n\n/**\n * ProfilePicture React Component\n *\n * Type-safe wrapper around the profile-picture web component\n */\nexport const ProfilePicture = React.forwardRef<\n HTMLElement,\n ProfilePictureProps\n>(\n (\n {\n src,\n alt,\n size,\n variant,\n border,\n borderWidth,\n borderColor,\n bgColor,\n bgGradient,\n ribbon,\n badge,\n loading,\n placeholder,\n placeholderColor,\n fallback,\n onLoad,\n onError,\n className,\n style,\n },\n ref\n ) => {\n return React.createElement(\"profile-picture\", {\n ref,\n src,\n alt,\n size,\n variant,\n border,\n \"border-width\": borderWidth,\n \"border-color\": borderColor,\n \"bg-color\": bgColor,\n \"bg-gradient\": bgGradient,\n ribbon,\n badge,\n loading,\n placeholder,\n \"placeholder-color\": placeholderColor,\n fallback,\n onLoad,\n onError,\n className,\n style,\n });\n }\n);\n\nProfilePicture.displayName = \"ProfilePicture\";\n\n// Re-export types\nexport type {\n Size,\n Variant,\n LoadingStrategy,\n PlaceholderType,\n RibbonConfig,\n BadgeConfig,\n};\n\nexport default ProfilePicture;\n\n// Export ProfilePictureGroup\nexport {\n type DropdownConfig,\n type GroupUserData,\n ProfilePictureGroup,\n type ProfilePictureGroupProps,\n type StackDirection,\n type TooltipConfig,\n} from \"./ProfilePictureGroup\";\n","/**\n * @grasco/profile-picture\n *\n * Main entry point - exports React wrapper for backwards compatibility\n * and convenience. For other frameworks, use the specific imports:\n *\n * - @grasco/profile-picture/angular\n * - @grasco/profile-picture/vue\n * - @grasco/profile-picture/svelte\n */\n\n// Auto-load styles when module is imported\nimport { loadStyles } from \"./core/loadStyles\";\n\nloadStyles();\n\n// ProfilePicture exports\nexport type {\n BadgeConfig,\n LoadingStrategy,\n PlaceholderType,\n Position,\n RibbonConfig,\n Size,\n Variant,\n} from \"./core/ProfilePicture\";\n// ProfilePictureGroup exports\nexport type {\n DropdownConfig,\n GroupUserData,\n ProfilePictureGroupProps,\n StackDirection,\n TooltipConfig,\n TooltipPosition,\n} from \"./core/types\";\nexport type { ProfilePictureProps } from \"./wrappers/react\";\nexport { ProfilePicture, ProfilePictureGroup } from \"./wrappers/react\";\n"]}
@@ -0,0 +1,260 @@
1
+ import * as lit_html from 'lit-html';
2
+ import { LitElement } from 'lit';
3
+
4
+ /**
5
+ * Profile Picture Component - Type Definitions
6
+ * Apple-inspired design system with modern 2025 aesthetics
7
+ */
8
+ type Size = "2xs" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl";
9
+ type Variant = "circle" | "rounded" | "squircle" | "square";
10
+ type Position = "top-left" | "top-right" | "bottom-left" | "bottom-right";
11
+ type LoadingStrategy = "lazy" | "eager";
12
+ type PlaceholderType = "shimmer" | "pulse" | "blur" | "skeleton" | "none";
13
+ type PresenceStatus = "online" | "away" | "busy" | "offline" | "dnd";
14
+ interface PresenceConfig {
15
+ /** Current status */
16
+ status: PresenceStatus;
17
+ /** Show animated ring */
18
+ animate?: boolean;
19
+ /** Ring thickness (1-3) */
20
+ thickness?: 1 | 2 | 3;
21
+ }
22
+ interface RibbonConfig {
23
+ /** Text displayed on the ribbon */
24
+ text: string;
25
+ /** Position of the ribbon */
26
+ position?: Position;
27
+ /** Text color (CSS color) */
28
+ color?: string;
29
+ /** Background color (CSS color or gradient) */
30
+ bgColor?: string;
31
+ /** Icon before text (emoji or symbol) */
32
+ icon?: string;
33
+ }
34
+ interface BadgeConfig {
35
+ /** Badge content (text, number, or empty for dot) */
36
+ content?: string | number;
37
+ /** Position of the badge */
38
+ position?: Position;
39
+ /** Text/icon color */
40
+ color?: string;
41
+ /** Background color */
42
+ bgColor?: string;
43
+ /** Enable pulse animation */
44
+ pulse?: boolean;
45
+ /** Enable glow effect */
46
+ glow?: boolean;
47
+ /** Max value to display (shows 99+ if exceeded) */
48
+ max?: number;
49
+ }
50
+ interface GlowConfig {
51
+ /** Glow color (defaults to border or bg color) */
52
+ color?: string;
53
+ /** Intensity (0-1) */
54
+ intensity?: number;
55
+ /** Animate the glow */
56
+ animate?: boolean;
57
+ }
58
+ interface RingConfig {
59
+ /** Show ring */
60
+ show: boolean;
61
+ /** Ring color or gradient */
62
+ color?: string;
63
+ /** Gradient colors for multi-color ring */
64
+ gradient?: string[];
65
+ /** Ring width */
66
+ width?: number;
67
+ /** Gap between ring and avatar */
68
+ gap?: number;
69
+ /** Animate (rotate for gradient) */
70
+ animate?: boolean;
71
+ }
72
+ interface InteractionConfig {
73
+ /** Enable hover effects */
74
+ hoverable?: boolean;
75
+ /** Enable press/click effects */
76
+ pressable?: boolean;
77
+ /** Show focus ring on focus */
78
+ focusable?: boolean;
79
+ /** Cursor style */
80
+ cursor?: "pointer" | "default" | "zoom-in";
81
+ }
82
+ type ShadowPreset = "none" | "sm" | "md" | "lg" | "glow";
83
+ /** Direction for stacking avatars */
84
+ type StackDirection = "ltr" | "rtl";
85
+ /** Tooltip position relative to avatar */
86
+ type TooltipPosition = "top" | "bottom" | "left" | "right";
87
+ /** Tooltip configuration */
88
+ interface TooltipConfig {
89
+ /** Enable/disable tooltip (default: true) */
90
+ enabled?: boolean;
91
+ /** Position of tooltip relative to avatar */
92
+ position?: TooltipPosition;
93
+ /** Delay before showing tooltip in ms (default: 300) */
94
+ delay?: number;
95
+ }
96
+ /** User data extracted from profile-picture elements */
97
+ interface GroupUserData {
98
+ /** User ID from data-user-id attribute */
99
+ id?: string;
100
+ /** User name from alt attribute */
101
+ name: string;
102
+ /** Image source URL */
103
+ src?: string;
104
+ /** Presence status from data-status attribute */
105
+ status?: PresenceStatus;
106
+ /** Reference to the profile-picture element */
107
+ element: HTMLElement;
108
+ /** Index in the group */
109
+ index: number;
110
+ /** Visual variant (circle, rounded, squircle, square) */
111
+ variant?: Variant;
112
+ /** Shadow preset */
113
+ shadow?: ShadowPreset;
114
+ /** Show border */
115
+ border?: boolean;
116
+ /** Border width (1-4) */
117
+ borderWidth?: 1 | 2 | 3 | 4;
118
+ /** Border color */
119
+ borderColor?: string;
120
+ /** Background color */
121
+ bgColor?: string;
122
+ /** Background gradient */
123
+ bgGradient?: string;
124
+ }
125
+ /** Dropdown configuration for overflow users */
126
+ interface DropdownConfig {
127
+ /** Max height of dropdown in px (default: 280) */
128
+ maxHeight?: number;
129
+ /** Show presence indicator dots (default: true) */
130
+ showPresence?: boolean;
131
+ /** Dropdown position (default: 'bottom') */
132
+ position?: "bottom" | "top";
133
+ }
134
+ /** Profile Picture Group Props */
135
+ interface ProfilePictureGroupProps {
136
+ /** Maximum visible avatars before showing counter (default: 4) */
137
+ max?: number;
138
+ /** Stack direction - ltr shows first on left (default: 'ltr') */
139
+ direction?: StackDirection;
140
+ /** Overlap amount as percentage 0-1 (default: 0.3) */
141
+ overlap?: number;
142
+ /** Avatar size - inherited by children (default: 'md') */
143
+ size?: Size | number;
144
+ /** Spacing between avatars in px (overrides overlap calculation) */
145
+ spacing?: number;
146
+ /** Tooltip configuration */
147
+ tooltip?: TooltipConfig;
148
+ /** Dropdown configuration for overflow users */
149
+ dropdown?: DropdownConfig;
150
+ /** Show add button (default: false) */
151
+ showAddButton?: boolean;
152
+ /** Add button label for accessibility */
153
+ addButtonLabel?: string;
154
+ /** Enable hover lift animation (default: true) */
155
+ animated?: boolean;
156
+ }
157
+
158
+ declare class ProfilePicture extends LitElement {
159
+ private static stylesInjected;
160
+ protected createRenderRoot(): this;
161
+ private static injectStylesOnce;
162
+ src: string;
163
+ alt: string;
164
+ size: Size | string;
165
+ variant: Variant;
166
+ shadow: ShadowPreset;
167
+ border: boolean;
168
+ borderWidth: 1 | 2 | 3 | 4;
169
+ borderColor: string;
170
+ bgColor?: string;
171
+ bgGradient?: string;
172
+ ring?: RingConfig;
173
+ presence?: PresenceConfig;
174
+ glow?: GlowConfig;
175
+ ribbon?: RibbonConfig;
176
+ badge?: BadgeConfig;
177
+ loading: LoadingStrategy;
178
+ placeholder: PlaceholderType;
179
+ placeholderColor: string;
180
+ fallback?: string;
181
+ interactive?: InteractionConfig;
182
+ private isLoaded;
183
+ private hasError;
184
+ private previousSrc;
185
+ private get pixelSize();
186
+ protected willUpdate(changedProperties: Map<string, unknown>): void;
187
+ private handleLoad;
188
+ private handleError;
189
+ private getContainerStyles;
190
+ private renderPlaceholder;
191
+ private renderFallback;
192
+ private renderImage;
193
+ private renderRing;
194
+ private renderPresence;
195
+ private renderBadge;
196
+ private renderRibbon;
197
+ render(): lit_html.TemplateResult<1>;
198
+ }
199
+
200
+ declare global {
201
+ interface HTMLElementTagNameMap {
202
+ "profile-picture": ProfilePicture;
203
+ }
204
+ }
205
+
206
+ declare class ProfilePictureGroup extends LitElement {
207
+ protected createRenderRoot(): this;
208
+ max: 4;
209
+ direction: StackDirection;
210
+ overlap: 0.3;
211
+ size: Size | string;
212
+ spacing?: number;
213
+ tooltip?: TooltipConfig;
214
+ dropdown?: DropdownConfig;
215
+ showAddButton: boolean;
216
+ addButtonLabel: string;
217
+ animated: true;
218
+ private users;
219
+ private dropdownOpen;
220
+ private tooltipData;
221
+ private tooltipTimeout;
222
+ private slotObserver;
223
+ private get pixelSize();
224
+ private get tooltipEnabled();
225
+ private get tooltipPosition();
226
+ private get tooltipDelay();
227
+ private get dropdownMaxHeight();
228
+ private get showPresence();
229
+ private get dropdownPosition();
230
+ connectedCallback(): void;
231
+ disconnectedCallback(): void;
232
+ private setupSlotObserver;
233
+ private updateUsers;
234
+ private handleAvatarClick;
235
+ private handleAvatarHover;
236
+ private handleAvatarLeave;
237
+ private clearTooltipTimeout;
238
+ private handleCounterClick;
239
+ private readonly handleBackdropClick;
240
+ private handleDropdownItemClick;
241
+ private handleAddClick;
242
+ private handleKeyDown;
243
+ private renderAvatar;
244
+ private renderProfilePicture;
245
+ private renderCounter;
246
+ private renderAddButton;
247
+ private renderTooltip;
248
+ private renderDropdown;
249
+ private renderDropdownItem;
250
+ private formatStatus;
251
+ render(): lit_html.TemplateResult<1>;
252
+ }
253
+
254
+ declare global {
255
+ interface HTMLElementTagNameMap {
256
+ "profile-picture-group": ProfilePictureGroup;
257
+ }
258
+ }
259
+
260
+ export type { BadgeConfig, DropdownConfig, GroupUserData, LoadingStrategy, PlaceholderType, Position, ProfilePictureGroupProps, RibbonConfig, Size, StackDirection, TooltipConfig, TooltipPosition, Variant };