apex-ui-kit 2.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/Licence.md +21 -0
  2. package/ReadMe.md +75 -0
  3. package/dist/ApexUI-Kit/templates/Avatar/Avatar.jsx +81 -0
  4. package/dist/ApexUI-Kit/templates/BeamBar/BeamBar.jsx +101 -0
  5. package/dist/ApexUI-Kit/templates/Cards/BasicCard.jsx +60 -0
  6. package/dist/ApexUI-Kit/templates/Carousel/Carousel.jsx +95 -0
  7. package/dist/ApexUI-Kit/templates/Carousel/DragCarousel.jsx +105 -0
  8. package/dist/ApexUI-Kit/templates/Carousel/ParallaxCarousel.jsx +161 -0
  9. package/dist/ApexUI-Kit/templates/DragCarousel/DragCarousel.jsx +105 -0
  10. package/dist/ApexUI-Kit/templates/EdgeGlowForm/EdgeGlowFrom.jsx +297 -0
  11. package/dist/ApexUI-Kit/templates/FlipProfile/FlipProfile.jsx +125 -0
  12. package/dist/ApexUI-Kit/templates/GlareCard/GlareCard.jsx +146 -0
  13. package/dist/ApexUI-Kit/templates/GlassCardStack/GlassCardStack.jsx +111 -0
  14. package/dist/ApexUI-Kit/templates/HoverText/HoverText.jsx +371 -0
  15. package/dist/ApexUI-Kit/templates/HyperCard/HyperCard.jsx +183 -0
  16. package/dist/ApexUI-Kit/templates/KineticThreadsBackground/KineticThreadBackground.jsx +249 -0
  17. package/dist/ApexUI-Kit/templates/LensFlareBackground/LensFlareBackground.jsx +268 -0
  18. package/dist/ApexUI-Kit/templates/LuminousParticleOcean/LuminousParticleOcean.jsx +155 -0
  19. package/dist/ApexUI-Kit/templates/NavDropDown/NavDropDown.jsx +114 -0
  20. package/dist/ApexUI-Kit/templates/NavMenu/NavMenu.jsx +153 -0
  21. package/dist/ApexUI-Kit/templates/OrbsBackground/FloatingOrbs.jsx +96 -0
  22. package/dist/ApexUI-Kit/templates/ParallaxCard/ParallaxCard.jsx +127 -0
  23. package/dist/ApexUI-Kit/templates/ParallaxCarousel/ParallaxCarousel.jsx +161 -0
  24. package/dist/ApexUI-Kit/templates/ParallaxProfile/ParallaxProfile.jsx +107 -0
  25. package/dist/ApexUI-Kit/templates/PointerFollower/PointerFollower.jsx +126 -0
  26. package/dist/ApexUI-Kit/templates/RainBackground/RainBackground.jsx +109 -0
  27. package/dist/ApexUI-Kit/templates/RippleBackground/RippleBackground.jsx +160 -0
  28. package/dist/ApexUI-Kit/templates/ScrollMarquee/ScrollMarquee.jsx +174 -0
  29. package/dist/ApexUI-Kit/templates/SmartGridCard/SmartGridCard.jsx +241 -0
  30. package/dist/ApexUI-Kit/templates/SmokeBackground/SmokeBackground.jsx +216 -0
  31. package/dist/ApexUI-Kit/templates/Testimonials/Testimonials.jsx +117 -0
  32. package/dist/ApexUI-Kit/templates/ThemeToggle/ThemeAnimation.js +252 -0
  33. package/dist/ApexUI-Kit/templates/ThemeToggle/ThemeConfig.js +8 -0
  34. package/dist/ApexUI-Kit/templates/ThemeToggle/ThemeToggle.css +560 -0
  35. package/dist/ApexUI-Kit/templates/ThemeToggle/ThemeToggle.jsx +118 -0
  36. package/dist/ApexUI-Kit/templates/ToolTip/ToolTip.jsx +85 -0
  37. package/dist/ApexUI-Kit/templates/WaterDropReveal/WaterDropReveal.jsx +151 -0
  38. package/dist/cli/index.d.ts +2 -0
  39. package/dist/cli/index.js +145 -0
  40. package/package.json +56 -0
package/Licence.md ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Mohan Kumar Dalei
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/ReadMe.md ADDED
@@ -0,0 +1,75 @@
1
+ # Apex UI Kit
2
+
3
+ Apex UI Kit is a modern, blazing-fast, beautifully animated React UI library built with Tailwind CSS, GSAP, and Framer Motion. Perfect for modern apps, portfolios, dashboards, and high-performance UIs.
4
+
5
+ ---
6
+
7
+ ## 🌐 Website & Docs
8
+
9
+ - **Main Site:** [https://apex-ui.in/](https://apex-ui.in/)
10
+ - **Introduction:** [https://apex-ui.in/components/docs/getting-started/introduction](https://apex-ui.in/components/docs/getting-started/introduction)
11
+ - **Components:** [https://apex-ui.in/components/glass-navbar](https://apex-ui.in/components/glass-navbar)
12
+
13
+ ## 🚀 Installation
14
+
15
+ ### 1. Install the package
16
+
17
+ ```bash
18
+ npm install apex-ui-kit
19
+ ```
20
+
21
+ ### 2. Add a component using the CLI
22
+
23
+ ```bash
24
+ npx apex-ui-kit add hyper-card
25
+ ```
26
+
27
+ ---
28
+
29
+ ## 🧩 Usage Example
30
+
31
+ ```jsx
32
+ import HyperCard from "./ApexUI-Kit/HyperCard/HyperCard.jsx";
33
+
34
+ const App = () => {
35
+ return (
36
+ <div>
37
+ <HyperCard
38
+ starColor="#9f7aea"
39
+ glow={true}
40
+ beamCount={10}
41
+ starCount={250}
42
+ />
43
+ </div>
44
+ );
45
+ };
46
+
47
+ export default App;
48
+ ```
49
+
50
+ ---
51
+
52
+ ## 📦 Features
53
+
54
+ - Modern, animated React components
55
+ - Easy CLI for adding components
56
+ - Built with Tailwind CSS, GSAP, Framer Motion
57
+ - Perfect for dashboards, portfolios, and modern web apps
58
+
59
+ ---
60
+
61
+ ## 📚 Documentation
62
+
63
+ - More components and usage: [Coming Soon]
64
+
65
+ ---
66
+
67
+ ## 🛠️ Contributing
68
+
69
+ Pull requests are welcome! For major changes, please open an issue first to discuss what you would like to change.
70
+
71
+ ---
72
+
73
+ ## 📝 License
74
+
75
+ MIT
@@ -0,0 +1,81 @@
1
+ import React from 'react';
2
+ import { motion } from "framer-motion";
3
+ const Avatar = ({ users }) => {
4
+ const containerVariants = {
5
+ hidden: { opacity: 0 },
6
+ visible: {
7
+ opacity: 1,
8
+ transition: {
9
+ staggerChildren: 0.15,
10
+ },
11
+ },
12
+ };
13
+
14
+ const itemVariants = {
15
+ hidden: { y: 20, opacity: 0 },
16
+ visible: {
17
+ y: 0,
18
+ opacity: 1,
19
+ transition: {
20
+ type: 'spring',
21
+ stiffness: 100,
22
+ },
23
+ },
24
+ };
25
+
26
+ // Helper to get initials and fallback color
27
+ const getInitial = (name) => name ? name.charAt(0).toUpperCase() : "?";
28
+ const getBgColor = (color) => color || "#4a5568";
29
+
30
+ return (
31
+ <div className="font-sans flex flex-col items-center justify-center">
32
+ <motion.div
33
+ className="flex -space-x-6"
34
+ variants={containerVariants}
35
+ initial="hidden"
36
+ animate="visible"
37
+ >
38
+ {users.map((user, index) => (
39
+ <motion.div key={index} variants={itemVariants}>
40
+ <motion.div
41
+ className="relative"
42
+ whileHover={{ scale: 1.1, zIndex: 10 }}
43
+ transition={{ type: 'spring', stiffness: 300, damping: 15 }}
44
+ >
45
+ {user.imageUrl ? (
46
+ <img
47
+ src={user.imageUrl}
48
+ alt={user.name}
49
+ className="w-20 h-20 object-cover rounded-full border-2"
50
+ style={{ borderColor: getBgColor(user.color) }}
51
+ onError={(e) => { e.target.onerror = null; e.target.src = ""; }}
52
+ />
53
+ ) : (
54
+ <div
55
+ className="w-20 h-20 flex items-center justify-center rounded-full border-4 text-5xl font-bold text-white/40"
56
+ style={{ backgroundColor: getBgColor(user.color), borderColor: getBgColor(user.color) }}
57
+ >
58
+ {getInitial(user.name)}
59
+ </div>
60
+ )}
61
+ <motion.span
62
+ className="absolute bottom-1 right-1 w-4 h-4 bg-green-400 rounded-full border-2 border-slate-900"
63
+ animate={{
64
+ scale: [1, 1.2, 1],
65
+ opacity: [0.8, 1, 0.8],
66
+ }}
67
+ transition={{
68
+ duration: 1.5,
69
+ repeat: Infinity,
70
+ ease: "easeInOut",
71
+ }}
72
+ />
73
+ </motion.div>
74
+ </motion.div>
75
+ ))}
76
+ </motion.div>
77
+ </div>
78
+ );
79
+ };
80
+
81
+ export default Avatar;
@@ -0,0 +1,101 @@
1
+ /* eslint-disable no-unused-vars */
2
+ import React, { useEffect, useState } from 'react';
3
+ import { motion, useAnimation } from 'framer-motion';
4
+
5
+ const BeamBar = ({
6
+ fromColor = "#a855f7",
7
+ viaColor = "#38bdf8",
8
+ toColor = "#06b6d4",
9
+ barWidth: maxBarWidth = 320, // Prop ko maxBarWidth ki tarah use karenge
10
+ barHeight = 8,
11
+ duration = 1.2,
12
+ pulseDuration = 2.5
13
+ }) => {
14
+ const controls = useAnimation();
15
+ const [pulse, setPulse] = useState(false);
16
+ const [beamOpacity, setBeamOpacity] = useState(0.1);
17
+
18
+ // Responsive width ke liye state
19
+ const [dynamicBarWidth, setDynamicBarWidth] = useState(0);
20
+
21
+ // Screen size change ko handle karne ke liye useEffect
22
+ useEffect(() => {
23
+ const updateWidth = () => {
24
+ // Screen width ka 80% ya maxBarWidth, jo bhi kam ho
25
+ const newWidth = Math.min(window.innerWidth * 0.8, maxBarWidth);
26
+ setDynamicBarWidth(newWidth);
27
+ };
28
+
29
+ updateWidth(); // Pehli baar set karne ke liye
30
+ window.addEventListener('resize', updateWidth); // Resize par update karne ke liye
31
+
32
+ // Cleanup function
33
+ return () => window.removeEventListener('resize', updateWidth);
34
+ }, [maxBarWidth]);
35
+
36
+ useEffect(() => {
37
+ // Jab dynamicBarWidth set ho jaye tab animation start karein
38
+ if (dynamicBarWidth > 0) {
39
+ controls.start({
40
+ width: dynamicBarWidth,
41
+ transition: { duration, ease: "easeInOut" }
42
+ });
43
+
44
+ // Animate beam opacity gradually during width expansion
45
+ let start = null;
46
+ function animateBeam(ts) {
47
+ if (!start) start = ts;
48
+ const elapsed = (ts - start) / 1000;
49
+ const progress = Math.min(elapsed / duration, 1);
50
+ setBeamOpacity(0.2 + 0.8 * progress); // from 0.2 to 1.0
51
+ if (progress < 1) {
52
+ requestAnimationFrame(animateBeam);
53
+ } else {
54
+ setPulse(true);
55
+ }
56
+ }
57
+ requestAnimationFrame(animateBeam);
58
+
59
+ // Cleanup
60
+ return () => {
61
+ setBeamOpacity(0.2);
62
+ setPulse(false);
63
+ };
64
+ }
65
+ }, [dynamicBarWidth, duration, controls]);
66
+
67
+ // Beam ka size ab bar ki width par depend karega
68
+ const beamWidth = dynamicBarWidth * 1.25;
69
+ const beamHeight = 800; // Ise bhi dynamic kar sakte hain agar zaroorat ho
70
+
71
+ return (
72
+ <div className="fixed top-10 left-0 w-full flex justify-center z-50 pointer-events-none">
73
+ <motion.div
74
+ initial={{ width: 0 }}
75
+ animate={controls}
76
+ // Class se 'hidden md:block' hataya gaya hai
77
+ className={`absolute top-0 left-1/2 -translate-x-1/2 rounded-md shadow-[0_0_10px_#fff,0_0_20px_#4f46e5,0_0_30px_#06b6d4] ${pulse ? 'animate-pulse' : ''}`}
78
+ style={{
79
+ height: barHeight,
80
+ background: `linear-gradient(to right, ${fromColor}, ${viaColor}, ${toColor})`,
81
+ animationDuration: pulse ? `${pulseDuration}s` : undefined,
82
+ }}
83
+ >
84
+ {/* Beam from Bar using pseudo-element */}
85
+ <div
86
+ className="absolute top-2 left-1/2 transform -translate-x-1/2 pointer-events-none z-0"
87
+ style={{
88
+ width: `${beamWidth}px`, // Dynamic width
89
+ height: `${beamHeight}px`, // Dynamic height (optional)
90
+ background: `linear-gradient(to bottom, rgba(111, 93, 245, 0.7), rgba(7, 7, 7, 0.3), transparent)`,
91
+ filter: "blur(100px)",
92
+ opacity: beamOpacity,
93
+ animation: pulse ? `glow ${pulseDuration}s infinite alternate` : undefined
94
+ }}
95
+ ></div>
96
+ </motion.div>
97
+ </div>
98
+ );
99
+ };
100
+
101
+ export default BeamBar;
@@ -0,0 +1,60 @@
1
+ /* eslint-disable no-unused-vars */
2
+ import React from "react";
3
+ import { motion } from "framer-motion";
4
+ import { SquareArrowOutUpRight, Wallpaper } from 'lucide-react';
5
+ import { NavLink } from "react-router-dom";
6
+ const ProfileCard = ({ title, summary, image, link }) => {
7
+ return (
8
+ <motion.div
9
+ initial={{ y: 20, opacity: 0 }}
10
+ animate={{ y: 0, opacity: 1 }}
11
+ transition={{ type: "spring", stiffness: 300, damping: 20 }}
12
+ className="w-72 rounded-2xl bg-slate-950 border border-gray-800 shadow-2xl overflow-hidden p-2 shadow-lime-700/20"
13
+ >
14
+ {/* Image */}
15
+ <div className="h-[30vh] w-full rounded-b-4xl rounded-t-lg overflow-hidden">
16
+ <motion.img
17
+ src={image}
18
+ alt={title}
19
+ className="w-full object-cover h-full"
20
+ whileHover={{ scale: 1.05 }}
21
+ transition={{ duration: 0.4 }}
22
+ />
23
+ </div>
24
+ {/* Content */}
25
+ <div className="p-4 flex flex-col gap-2">
26
+ <h2 className="text-lg font-bold flex items-center gap-3 text-[var(--color-pages-side-active-text)]">
27
+ <Wallpaper size={18} /> {title}
28
+ </h2>
29
+
30
+ <p className="text-sm text-gray-400 leading-relaxed">
31
+ {summary}
32
+ </p>
33
+
34
+ {/* Stats + Button */}
35
+ <div className="flex items-center justify-center mt-3 transition-all duration-150 ease-in-out">
36
+ {/* Visit Button */}
37
+ <NavLink
38
+ to={link}
39
+ className="px-7 py-1.5 rounded-full bg-lime-600 text-white font-medium shadow hover:bg-lime-500/90 active:scale-95 transition-all duration-150 ease-in-out flex items-center justify-center gap-2 ring-4 ring-lime-600/30 active:ring-lime-600"
40
+ >
41
+ Visit <SquareArrowOutUpRight size={15} />
42
+ </NavLink>
43
+ </div>
44
+ </div>
45
+ </motion.div>
46
+ );
47
+ };
48
+
49
+ // Wrapper to map array of objects
50
+ const ProfileCardList = ({ data }) => {
51
+ return (
52
+ <div className="flex flex-wrap gap-3 justify-center items-center">
53
+ {data.map((item, index) => (
54
+ <ProfileCard key={index} {...item} />
55
+ ))}
56
+ </div>
57
+ );
58
+ };
59
+
60
+ export default ProfileCardList;
@@ -0,0 +1,95 @@
1
+ import React, { useState } from 'react';
2
+
3
+ // To use Framer Motion in this environment, we'll import it from a CDN.
4
+ // In a local project, you would typically use: `npm install framer-motion`
5
+ import { motion } from 'framer-motion';
6
+ import { ArrowLeft, ArrowRight } from 'lucide-react';
7
+
8
+ // --- Custom Parallax Carousel Component ---
9
+ const ParallaxCarousel = ({ slides }) => {
10
+ const [activeIndex, setActiveIndex] = useState(0);
11
+
12
+ const handleNext = () => {
13
+ setActiveIndex((prevIndex) => (prevIndex + 1) % slides.length);
14
+ };
15
+
16
+ const handlePrev = () => {
17
+ setActiveIndex((prevIndex) => (prevIndex - 1 + slides.length) % slides.length);
18
+ };
19
+
20
+
21
+ return (
22
+ <div className="w-full flex flex-col items-center px-2">
23
+ {/* 3D Carousel Container without drag/grab */}
24
+ <motion.div
25
+ className="relative w-full h-[440px] portrait:h-[480px] mb-8"
26
+ style={{ perspective: '1200px', transformStyle: 'preserve-3d' }}
27
+ >
28
+ {slides.map((slide, index) => {
29
+ let positionOffset = index - activeIndex;
30
+ if (positionOffset > slides.length / 2) {
31
+ positionOffset -= slides.length;
32
+ } else if (positionOffset < -slides.length / 2) {
33
+ positionOffset += slides.length;
34
+ }
35
+
36
+ const isVisible = Math.abs(positionOffset) <= 2;
37
+
38
+ return (
39
+ <motion.div
40
+ key={index}
41
+ className={`absolute w-full h-[440px] portrait:w-full portrait:h-[480px] top-0 left-0 portrait:left-0 portrait:top-0 bg-slate-900 rounded-2xl overflow-hidden border-2 border-slate-800 md:w-[50%] md:h-[450px] md:top-[50px] md:left-[25%]`}
42
+ initial={false}
43
+ animate={{
44
+ translateX: `${positionOffset * 50}%`,
45
+ translateZ: -Math.abs(positionOffset) * 250,
46
+ scale: 1 - Math.abs(positionOffset) * 0.15,
47
+ opacity: isVisible ? (1 - Math.abs(positionOffset) * 0.35) : 0,
48
+ zIndex: slides.length - Math.abs(positionOffset),
49
+ }}
50
+ transition={{ type: 'spring', stiffness: 260, damping: 30 }}
51
+ style={{ transformStyle: 'preserve-3d' }}
52
+ >
53
+ {/* Slide Content */}
54
+ <div className="absolute inset-0 w-full h-full">
55
+ <img
56
+ src={slide.imageUrl}
57
+ alt={slide.title}
58
+ className="w-full h-full object-cover opacity-50 pointer-events-none"
59
+ />
60
+ </div>
61
+ <div
62
+ className="relative z-10 flex flex-col justify-end h-full p-8 text-white"
63
+ style={{ transform: 'translateZ(60px)' }} // Content ko 3D space mein aage rakhta hai
64
+ >
65
+ <h2 className="text-3xl font-bold">{slide.title}</h2>
66
+ <p className="text-lime-400 mt-1">{slide.subtitle}</p>
67
+ <p className="text-slate-300 mt-4 text-sm leading-relaxed">{slide.text}</p>
68
+ </div>
69
+ </motion.div>
70
+ );
71
+ })}
72
+ </motion.div>
73
+
74
+ {/* Navigation Buttons at the bottom */}
75
+ <div className="flex items-center justify-center gap-4 mt-10">
76
+ <motion.button
77
+ onClick={handlePrev}
78
+ className="bg-slate-800/80 hover:bg-slate-800 rounded-full p-3 transition-colors text-slate-400 hover:text-lime-400"
79
+ whileTap={{ scale: 0.9 }}
80
+ >
81
+ <ArrowLeft size={24} />
82
+ </motion.button>
83
+ <motion.button
84
+ onClick={handleNext}
85
+ className="bg-slate-800/80 hover:bg-slate-800 rounded-full p-3 transition-colors text-slate-400 hover:text-lime-400"
86
+ whileTap={{ scale: 0.9 }}
87
+ >
88
+ <ArrowRight size={24} />
89
+ </motion.button>
90
+ </div>
91
+ </div>
92
+ );
93
+ };
94
+
95
+ export default ParallaxCarousel;
@@ -0,0 +1,105 @@
1
+ import React, { useState, useEffect, useRef } from 'react';
2
+
3
+ // To use GSAP in this environment, we'll import it from a CDN.
4
+ // In a local project: `npm install gsap`
5
+ import { gsap } from 'gsap';
6
+ import { Draggable } from 'gsap/Draggable';
7
+
8
+ // GSAP Draggable plugin ko register karna zaroori hai
9
+ gsap.registerPlugin(Draggable);
10
+
11
+ // --- GSAP Drag Carousel Component ---
12
+ const DragCarousel = ({ images }) => {
13
+ const [activeIndex, setActiveIndex] = useState(0);
14
+ const carouselRef = useRef(null);
15
+ const cardsRef = useRef([]);
16
+ const dragProxyRef = useRef(null);
17
+ useEffect(() => {
18
+ const cards = cardsRef.current;
19
+ gsap.to(cards, {
20
+ duration: 0.4,
21
+ ease: 'power4.Out',
22
+ stagger: 0.05,
23
+ // Har card ke liye naya transform calculate karta hai
24
+ transform: (i) => {
25
+ let positionOffset = i - activeIndex;
26
+ if (positionOffset > images.length / 2) {
27
+ positionOffset -= images.length;
28
+ } else if (positionOffset < -images.length / 2) {
29
+ positionOffset += images.length;
30
+ }
31
+
32
+ const translateX = positionOffset * 50;
33
+ const translateZ = -Math.abs(positionOffset) * 250;
34
+ const scale = 1 - Math.abs(positionOffset) * 0.15;
35
+
36
+ return `translateX(${translateX}%) translateZ(${translateZ}px) scale(${scale})`;
37
+ },
38
+ zIndex: (i) => {
39
+ let positionOffset = i - activeIndex;
40
+ if (positionOffset > images.length / 2) positionOffset -= images.length;
41
+ if (positionOffset < -images.length / 2) positionOffset += images.length;
42
+ return images.length - Math.abs(positionOffset);
43
+ },
44
+ opacity: (i) => {
45
+ let positionOffset = i - activeIndex;
46
+ if (positionOffset > images.length / 2) positionOffset -= images.length;
47
+ if (positionOffset < -images.length / 2) positionOffset += images.length;
48
+ return Math.abs(positionOffset) > 2 ? 0 : 1;
49
+ }
50
+ });
51
+ }, [activeIndex, images.length]);
52
+
53
+ // GSAP Draggable ko setup karta hai
54
+ useEffect(() => {
55
+ // BUG FIX: Draggable ab proxy element par lagaya gaya hai
56
+ const draggableInstance = Draggable.create(dragProxyRef.current, {
57
+ type: "x",
58
+ trigger: carouselRef.current,
59
+ inertia: true,
60
+ cursor: 'grab',
61
+ activeCursor: 'grabbing',
62
+ onDragEnd: function () {
63
+ gsap.to(this.target, { x: 0, duration: 0.3 });
64
+ if (this.getDirection("start") === "left") {
65
+ setActiveIndex(prev => (prev + 1) % images.length);
66
+ } else if (this.getDirection("start") === "right") {
67
+ setActiveIndex(prev => (prev - 1 + images.length) % images.length);
68
+ }
69
+ }
70
+ });
71
+
72
+ // Cleanup function
73
+ return () => {
74
+ if (draggableInstance && draggableInstance[0]) {
75
+ draggableInstance[0].kill();
76
+ }
77
+ };
78
+ }, [images.length]);
79
+
80
+ return (
81
+ <div
82
+ ref={carouselRef}
83
+ className="relative w-full h-[490px] lg:h-[590px] cursor-grab"
84
+ style={{ perspective: '1200px', transformStyle: 'preserve-3d' }}
85
+ >
86
+ <div ref={dragProxyRef} className="absolute inset-0 z-20"></div>
87
+
88
+ {images.map((src, index) => (
89
+ <div
90
+ key={index}
91
+ ref={el => cardsRef.current[index] = el}
92
+ className="card-item absolute h-[480px] w-[300px] lg:h-[550px] lg:w-[350px] rounded-xl overflow-hidden shadow-2xl top-[25px] -left-4 md:left-36 lg:left-70"
93
+ >
94
+ <img
95
+ src={src}
96
+ alt={`carousel-item-${index}`}
97
+ className="w-full h-full object-cover pointer-events-none"
98
+ />
99
+ </div>
100
+ ))}
101
+ </div>
102
+ );
103
+ };
104
+
105
+ export default DragCarousel;