UNPKG

lightswind

Version:

A collection of beautifully crafted React Components, Blocks & Templates for Modern Developers. Create stunning web applications effortlessly by using our 160+ professional and animated react components.

106 lines 5.79 kB
"use strict"; "use client"; Object.defineProperty(exports, "__esModule", { value: true }); exports.AngledSlider = void 0; const jsx_runtime_1 = require("react/jsx-runtime"); const react_1 = require("react"); const framer_motion_1 = require("framer-motion"); const utils_1 = require("@/components/lib/utils"); // ─── Angled Slider ────────────────────────────────────────────────────────── const cardVariants = { offHover: (angle) => ({ rotateY: angle, z: 60, // Ensure card is in front of container plane (which blocks -Z events) opacity: 0.9, scale: 1, zIndex: 30, // Higher than potential overlays transition: { type: "spring", mass: 3, stiffness: 400, damping: 50 } }), onHover: (hoverScale) => ({ rotateY: 0, z: 120, // Pop out further opacity: 1, scale: hoverScale, zIndex: 50, transition: { type: "spring", mass: 3, stiffness: 400, damping: 50 } }) }; const AngledCard = ({ item, angle, hoverScale, cardWidth }) => { const [isHovered, setIsHovered] = (0, react_1.useState)(false); return ((0, jsx_runtime_1.jsx)(framer_motion_1.motion.div, { className: "relative flex-shrink-0 group overflow-visible cursor-pointer", style: { width: cardWidth, height: "100%", transformStyle: "preserve-3d", }, custom: isHovered ? hoverScale : angle, variants: cardVariants, initial: "offHover", animate: isHovered ? "onHover" : "offHover", onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), children: (0, jsx_runtime_1.jsxs)("div", { className: "relative h-full w-full overflow-hidden border border-white/10 bg-muted \r\n min-h-[300px] shadow-2xl", children: [(0, jsx_runtime_1.jsx)("img", { src: item.url, alt: item.alt || "Slider Image", className: "absolute inset-0 h-full w-full object-cover transition-transform duration-500 group-hover:scale-110" }), item.title && ((0, jsx_runtime_1.jsx)("div", { className: "absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/80 to-transparent p-4 text-white opacity-0 transition-opacity duration-300 group-hover:opacity-100", children: (0, jsx_runtime_1.jsx)("h3", { className: "text-lg font-bold", children: item.title }) }))] }) })); }; const AngledSlider = ({ items, speed = 40, direction = "left", containerHeight = "400px", cardWidth = "300px", gap = "40px", angle = 20, hoverScale = 1.05, className, }) => { const [width, setWidth] = (0, react_1.useState)(0); const containerRef = (0, react_1.useRef)(null); const x = (0, framer_motion_1.useMotionValue)(0); const [isHovered, setIsHovered] = (0, react_1.useState)(false); // Duplicate items for infinite loop effect // We need enough duplicates to fill the screen + buffer const duplicatedItems = [...items, ...items, ...items]; (0, react_1.useEffect)(() => { const calculateWidth = () => { // Fallback to prop-based calculation if ref is not quite ready or layout is shifting // This is generally safer for known fixed-width items const numWidth = parseInt(cardWidth?.toString().replace("px", "") || "300"); const numGap = parseInt(gap?.toString().replace("px", "") || "40"); if (!isNaN(numWidth) && !isNaN(numGap)) { const calculatedWidth = (numWidth + numGap) * items.length; setWidth(calculatedWidth); } else if (containerRef.current) { const scrollWidth = containerRef.current.scrollWidth; setWidth(scrollWidth / 3); } }; calculateWidth(); window.addEventListener('resize', calculateWidth); return () => window.removeEventListener('resize', calculateWidth); }, [items, cardWidth, gap]); (0, react_1.useEffect)(() => { if (width <= 0) return; const startX = direction === "left" ? 0 : -width; const endX = direction === "left" ? -width : 0; if (isHovered) return; const runAnimation = () => { const currentX = x.get(); const totalDist = width; const dist = Math.abs(endX - currentX); const duration = speed * (dist / totalDist); const controls = (0, framer_motion_1.animate)(x, endX, { duration: duration, ease: "linear", onComplete: () => { x.set(startX); runAnimation(); } }); return controls; }; const animation = runAnimation(); return () => { animation.stop(); }; }, [width, speed, direction, isHovered, x]); return ((0, jsx_runtime_1.jsx)("div", { className: (0, utils_1.cn)("relative w-full overflow-hidden bg-background py-10 perspective-1000", className), style: { height: containerHeight, perspective: "1000px", // Essential for 3D effect }, onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), children: (0, jsx_runtime_1.jsx)(framer_motion_1.motion.div, { ref: containerRef, className: "flex items-center", style: { x, gap, transformStyle: "preserve-3d" }, children: duplicatedItems.map((item, index) => ((0, jsx_runtime_1.jsx)(AngledCard, { item: item, angle: angle, hoverScale: hoverScale, cardWidth: cardWidth }, `${item.id}-${index}`))) }) })); }; exports.AngledSlider = AngledSlider; //# sourceMappingURL=angled-slider.js.map