diff --git a/src/components/cardStack/CardStack.tsx b/src/components/cardStack/CardStack.tsx index be1a7bc..3003a8a 100644 --- a/src/components/cardStack/CardStack.tsx +++ b/src/components/cardStack/CardStack.tsx @@ -1,69 +1,229 @@ -import React, { useEffect, useRef, useState } from 'react'; +"use client"; -interface TimelineBaseProps { - items: Array<{ - id: string | number; - content: React.ReactNode; - media: React.ReactNode; - reverse?: boolean; - }>; - reverse?: boolean; - className?: string; - containerClassName?: string; - itemClassName?: string; - mediaWrapperClassName?: string; - numberClassName?: string; - contentWrapperClassName?: string; - gapClassName?: string; - ariaLabel?: string; -} +import { memo, Children } from "react"; +import { CardStackProps } from "./types"; +import GridLayout from "./layouts/grid/GridLayout"; +import AutoCarousel from "./layouts/carousels/AutoCarousel"; +import ButtonCarousel from "./layouts/carousels/ButtonCarousel"; +import TimelineBase from "./layouts/timelines/TimelineBase"; +import { gridConfigs } from "./layouts/grid/gridConfigs"; -const CardStack = React.forwardRef( - ( - { - items, - reverse = false, - className, - containerClassName, - itemClassName, - mediaWrapperClassName, - numberClassName, - contentWrapperClassName, - gapClassName, - ariaLabel = 'Card stack timeline', - }, - ref - ) => { - const [windowHeight, setWindowHeight] = useState(0); +const CardStack = ({ + children, + mode = "buttons", + gridVariant = "uniform-all-items-equal", + uniformGridCustomHeightClasses, + gridRowsClassName, + itemHeightClassesOverride, + animationType, + supports3DAnimation = false, + title, + titleSegments, + description, + tag, + tagIcon, + tagAnimation, + buttons, + buttonAnimation, + textboxLayout = "default", + useInvertedBackground, + carouselThreshold = 5, + bottomContent, + className = "", + containerClassName = "", + gridClassName = "", + carouselClassName = "", + carouselItemClassName = "", + controlsClassName = "", + textBoxClassName = "", + titleClassName = "", + titleImageWrapperClassName = "", + titleImageClassName = "", + descriptionClassName = "", + tagClassName = "", + buttonContainerClassName = "", + buttonClassName = "", + buttonTextClassName = "", + ariaLabel = "Card stack", +}: CardStackProps) => { + const childrenArray = Children.toArray(children); + const itemCount = childrenArray.length; - useEffect(() => { - setWindowHeight(typeof window !== 'undefined' ? window.innerHeight : 0); - }, []); + // Check if the current grid config has gridRows defined + const gridConfig = gridConfigs[gridVariant]?.[itemCount]; + const hasFixedGridRows = gridConfig && 'gridRows' in gridConfig && gridConfig.gridRows; + + // If grid has fixed row heights and we have uniformGridCustomHeightClasses, + // we need to use min-h-0 on md+ to prevent conflicts + let adjustedHeightClasses = uniformGridCustomHeightClasses; + if (hasFixedGridRows && uniformGridCustomHeightClasses) { + // Extract the mobile min-height and add md:min-h-0 + const mobileMinHeight = uniformGridCustomHeightClasses.split(' ')[0]; + adjustedHeightClasses = `${mobileMinHeight} md:min-h-0`; + } + + // Timeline layout for zigzag pattern (works best with 3-6 items) + if (gridVariant === "timeline" && itemCount >= 3 && itemCount <= 6) { + // Convert depth-3d to scale-rotate for timeline (doesn't support 3D) + const timelineAnimationType = animationType === "depth-3d" ? "scale-rotate" : animationType; + + return ( + + {childrenArray} + + ); + } + + // Use grid for items below threshold, carousel for items at or above threshold + // Timeline with 7+ items will also use carousel + const useCarousel = itemCount >= carouselThreshold || (gridVariant === "timeline" && itemCount > 6); + + // Grid layout for 1-4 items + if (!useCarousel) { + return ( + + {childrenArray} + + ); + } + + // Auto-scroll carousel for 5+ items + if (mode === "auto") { + // Convert depth-3d to scale-rotate for carousel (doesn't support 3D) + const carouselAnimationType = animationType === "depth-3d" ? "scale-rotate" : animationType; + + return ( + + {childrenArray} + + ); + } + + // Button-controlled carousel for 5+ items + // Convert depth-3d to scale-rotate for carousel (doesn't support 3D) + const carouselAnimationType = animationType === "depth-3d" ? "scale-rotate" : animationType; return ( -
- {items.map((item, index) => ( -
-
- {item.media} -
-
- - {item.id} - - {item.content} -
-
- ))} -
+ + {childrenArray} + ); - } -); +}; -CardStack.displayName = 'CardStack'; +CardStack.displayName = "CardStack"; -export default CardStack; +export default memo(CardStack);