File size: 2,137 Bytes
b59aa07
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
import React from "react";
import { ChevronLeft } from "#/assets/chevron-left";
import { ChevronRight } from "#/assets/chevron-right";
import { ImagePreview } from "./image-preview";
import { cn } from "#/utils/utils";

interface ImageCarouselProps {
  size: "small" | "large";
  images: string[];
  onRemove?: (index: number) => void;
}

export function ImageCarousel({
  size = "small",
  images,
  onRemove,
}: ImageCarouselProps) {
  const scrollContainerRef = React.useRef<HTMLDivElement>(null);
  const [isScrollable, setIsScrollable] = React.useState(false);
  const [isAtStart, setIsAtStart] = React.useState(true);
  const [isAtEnd, setIsAtEnd] = React.useState(false);

  React.useEffect(() => {
    const scrollContainer = scrollContainerRef.current;

    if (scrollContainer) {
      const hasScroll =
        scrollContainer.scrollWidth > scrollContainer.clientWidth;
      setIsScrollable(hasScroll);
    }
  }, [images]);

  const handleScroll = (event: React.UIEvent<HTMLDivElement>) => {
    const scrollContainer = event.currentTarget;
    setIsAtStart(scrollContainer.scrollLeft === 0);
    setIsAtEnd(
      scrollContainer.scrollLeft + scrollContainer.clientWidth ===
        scrollContainer.scrollWidth,
    );
  };

  return (
    <div data-testid="image-carousel" className="relative">
      {isScrollable && (
        <div className="absolute right-full transform top-1/2 -translate-y-1/2">
          <ChevronLeft active={!isAtStart} />
        </div>
      )}
      <div
        ref={scrollContainerRef}
        onScroll={handleScroll}
        className={cn(
          "flex overflow-x-auto",
          size === "small" && "gap-2",
          size === "large" && "gap-4",
        )}
      >
        {images.map((src, index) => (
          <ImagePreview
            key={index}
            size={size}
            src={src}
            onRemove={onRemove && (() => onRemove(index))}
          />
        ))}
      </div>
      {isScrollable && (
        <div className="absolute left-full transform top-1/2 -translate-y-1/2">
          <ChevronRight active={!isAtEnd} />
        </div>
      )}
    </div>
  );
}