'use client'; import React, { useState, useCallback, useMemo } from 'react'; import { twMerge } from 'tailwind-merge'; import clsx from 'clsx'; import { Image } from '@akinon/next/components/image'; import { Link } from '@akinon/next/components/link'; import type { ListHoverImageProps, IndicatorProps, HoverZoneProps } from '../types'; import { mergeSettings } from '../utils'; function HoverZones({ count, href, onHover, customStyles }: HoverZoneProps) { return (
{Array.from({ length: count }, (_, index) => ( onHover(index)} aria-label={`View image ${index + 1}`} /> ))}
); } function Indicators({ count, activeIndex, onSelect, customStyles, customRenderers }: IndicatorProps) { if (count <= 1) return null; if (customRenderers?.renderIndicator) { return ( <> {customRenderers.renderIndicator({ count, activeIndex, onSelect })} ); } return (
); } export function ListHoverImage({ images, href, alt, width, height, fill, sizes, aspectRatio, maxImages, fallbackImage, className, settings: userSettings }: ListHoverImageProps) { const settings = mergeSettings(userSettings); const resolvedMaxImages = maxImages ?? settings.maxImages; const resolvedFallback = fallbackImage ?? settings.fallbackImage; const visibleImages = useMemo( () => images?.slice(0, resolvedMaxImages) ?? [], [images, resolvedMaxImages] ); const initialImageUrl = visibleImages[0]?.image || resolvedFallback; const [activeIndex, setActiveIndex] = useState(0); const [currentImageUrl, setCurrentImageUrl] = useState(initialImageUrl); const handleImageChange = useCallback( (index: number) => { setActiveIndex(index); setCurrentImageUrl(visibleImages[index]?.image || resolvedFallback); }, [visibleImages, resolvedFallback] ); const imageElement = settings.customRenderers.renderImage ? ( settings.customRenderers.renderImage({ src: currentImageUrl, alt, width, height, fill, sizes, aspectRatio }) ) : ( {alt} ); return (
{imageElement}
); }