import type { CSSProperties } from 'react'; export const normalizeIndex = (index: number, itemCount: number): number => { if (itemCount <= 0) return 0; return ((index % itemCount) + itemCount) % itemCount; }; export const getCarouselMovementMessage = (normalizedIndex: number, itemCount: number): string => { if (itemCount <= 0) return ''; return `Slide ${normalizedIndex + 1} of ${itemCount}`; }; export const getContentAnnouncementMessage = ( media: { source: string; username?: string; products?: Array<{ id: string }>; productsLinked?: { exact?: string[]; similar?: string[]; }; }, currentIndex: number, totalCount: number, ): string => { const socialNetwork = media.source.charAt(0).toUpperCase() + media.source.slice(1); let message = `Slide ${currentIndex + 1} of ${totalCount}. Content created on ${socialNetwork}`; if (media.username) { message += ` by ${media.username}`; } // Calculate exact and similar product counts from actual products array const exactProductIds = new Set(media.productsLinked?.exact || []); const products = media.products || []; const exactCount = products.filter((p) => exactProductIds.has(p.id)).length; const similarCount = products.length - exactCount; if (exactCount > 0 || similarCount > 0) { const exactText = exactCount === 1 ? 'exact product' : 'exact products'; const similarText = similarCount === 1 ? 'similar product' : 'similar products'; message += `. ${exactCount} ${exactText} linked and ${similarCount} ${similarText} linked`; } return message; }; export const getSrOnlyStyle = (): CSSProperties => ({ position: 'absolute', width: 1, height: 1, padding: 0, margin: -1, overflow: 'hidden', clip: 'rect(0, 0, 0, 0)', whiteSpace: 'nowrap', border: 0, }); export const getCarouselCloneAccessibilityProps = (isClone: boolean): Record => { if (!isClone) return {}; // `inert` is not in TS lib.dom everywhere, so we return it as an untyped prop. return { 'aria-hidden': true, 'data-carousel-clone': 'true', inert: '', }; };