UNPKG

@gambito-corp/mbs-library

Version:

Librería de componentes React reutilizables - Sistema de diseño modular y escalable

163 lines (130 loc) 4.41 kB
import { IMAGE_VARIANTS, IMAGE_SIZES, IMAGE_SHAPES, AVATAR_STATUS } from './Image.constants.js'; /** * Genera las clases BEM para el componente Image */ export const getImageBEMClasses = ({ variant = 'thumbnail', size = 'medium', shape = 'rounded', loading = false, error = false, hover = false, className = '' }) => { const base = 'image'; const mods = []; // ✅ CORREGIDO: Avatar siempre es circular let finalShape = shape; if (variant === 'avatar') { finalShape = 'circle'; } // Variante if (variant !== 'thumbnail') { mods.push(`${base}--${variant}`); } // Tamaño if (size !== 'medium') { mods.push(`${base}--${size}`); } // Forma (avatar siempre será circle) if (finalShape !== 'rounded') { mods.push(`${base}--${finalShape}`); } // Estados if (loading) mods.push(`${base}--loading`); if (error) mods.push(`${base}--error`); if (hover) mods.push(`${base}--hover`); return [base, ...mods, className].filter(Boolean).join(' '); }; /** * Genera clases BEM para el contenedor */ export const getImageContainerBEMClasses = (positioned = false) => { const base = 'image-container'; const mods = []; if (positioned) mods.push(`${base}--positioned`); return [base, ...mods].filter(Boolean).join(' '); }; /** * Genera clases BEM para el status indicator */ export const getStatusIndicatorBEMClasses = (status, size = 'medium') => { const base = 'image__status'; const mods = []; if (status !== 'online') mods.push(`${base}--${status}`); if (size !== 'medium') mods.push(`${base}--${size}`); return [base, ...mods].filter(Boolean).join(' '); }; /** * Genera clases BEM para fallback */ export const getFallbackBEMClasses = (type = 'placeholder') => { const base = 'image__fallback'; const mods = []; if (type !== 'placeholder') mods.push(`${base}--${type}`); return [base, ...mods].filter(Boolean).join(' '); }; /** * Extrae iniciales del nombre */ export const getInitials = (name) => { if (!name) return '?'; const words = name.trim().split(' '); if (words.length === 1) { return words[0].charAt(0).toUpperCase(); } return words .slice(0, 2) .map(word => word.charAt(0).toUpperCase()) .join(''); }; /** * Valida si una URL de imagen es válida */ export const isValidImageUrl = (url) => { if (!url || typeof url !== 'string') return false; try { new URL(url); return true; } catch { return false; } }; /** * Genera srcSet para imágenes responsive */ export const generateSrcSet = (baseSrc, sizes = [1, 2, 3]) => { if (!baseSrc) return ''; return sizes .map(scale => `${baseSrc}?w=${scale}x ${scale}x`) .join(', '); }; /** * Obtiene el color del status */ export const getStatusColor = (status) => { return AVATAR_STATUS[status]?.color || AVATAR_STATUS.offline.color; }; /** * Valida las props del componente Image */ export const validateImageProps = (props) => { const warnings = []; const errors = []; if (props.variant && !Object.keys(IMAGE_VARIANTS).includes(props.variant)) { warnings.push(`Variante "${props.variant}" no es válida`); } if (props.size && !Object.keys(IMAGE_SIZES).includes(props.size)) { warnings.push(`Tamaño "${props.size}" no es válido`); } if (props.shape && !Object.keys(IMAGE_SHAPES).includes(props.shape)) { warnings.push(`Forma "${props.shape}" no es válida`); } if (props.variant === 'avatar' && props.status && !Object.keys(AVATAR_STATUS).includes(props.status)) { warnings.push(`Status "${props.status}" no es válido para avatar`); } if (!props.src && !props.fallback) { errors.push('Se requiere src o fallback'); } return { warnings, errors, isValid: errors.length === 0 }; };