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.

125 lines 8.41 kB
"use strict"; "use client"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MorphingNavigation = 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"); const MorphingNavigation = ({ links, scrollThreshold = 100, enablePageBlur = true, theme = "glass", backgroundColor, textColor, borderColor, initialTop = 70, compactTop = 20, animationDuration = 1, className, onLinkClick, onMenuToggle, enableSmoothTransitions = true, customHamburgerIcon, disableAutoMorph = false, }) => { const [isSticky, setIsSticky] = (0, react_1.useState)(false); const [isMenuOpen, setIsMenuOpen] = (0, react_1.useState)(false); const [isMobile, setIsMobile] = (0, react_1.useState)(false); const navRef = (0, react_1.useRef)(null); (0, react_1.useEffect)(() => { const handleResize = () => { setIsMobile(window.innerWidth < 768); }; handleResize(); window.addEventListener("resize", handleResize); return () => window.removeEventListener("resize", handleResize); }, []); const getThemeStyles = (0, react_1.useCallback)(() => { switch (theme) { case "dark": return { nav: "bg-black/80 border-gray-800", text: "text-white", button: "bg-black/50 border-gray-700", }; case "light": return { nav: "bg-white/80 border-gray-200", text: "text-gray-900", button: "bg-white/50 border-gray-300", }; case "custom": return { nav: backgroundColor ? "" : "bg-white/5 border-white/10", text: textColor ? "" : "text-white", button: "bg-black/30 border-white/10", }; case "glass": default: return { nav: "bg-white/5 border-white/10", text: "text-foreground", button: "bg-black/30 border-white/10", }; } }, [theme, backgroundColor, textColor]); const themeStyles = getThemeStyles(); (0, react_1.useEffect)(() => { if (disableAutoMorph && !isMobile) return; const handleScroll = () => { if (isMobile) { setIsSticky(true); setIsMenuOpen(false); } else { setIsSticky(window.scrollY >= scrollThreshold); setIsMenuOpen(false); } }; window.addEventListener("scroll", handleScroll); return () => window.removeEventListener("scroll", handleScroll); }, [scrollThreshold, disableAutoMorph, isMobile]); const handleMenuToggle = () => { const open = !isMenuOpen; setIsMenuOpen(open); if (isMobile && open) { setIsSticky(true); } else if (isMobile && !open) { setIsSticky(window.scrollY >= scrollThreshold); } else { setIsSticky(false); } onMenuToggle?.(open); }; const handleLinkClick = (link, e) => { e.preventDefault(); setIsMenuOpen(false); onLinkClick?.(link); if (enableSmoothTransitions) { const target = document.querySelector(link.href); if (target) { target.scrollIntoView({ behavior: "smooth", block: "start" }); } } }; (0, react_1.useEffect)(() => { const handleClickOutside = (e) => { if (navRef.current && !navRef.current.contains(e.target) && isMenuOpen) { setIsMenuOpen(false); } }; document.addEventListener("click", handleClickOutside); return () => document.removeEventListener("click", handleClickOutside); }, [isMenuOpen]); const customStyles = { backgroundColor: theme === "custom" ? backgroundColor : undefined, color: theme === "custom" ? textColor : undefined, borderColor: theme === "custom" ? borderColor : undefined, }; return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(framer_motion_1.AnimatePresence, { children: enablePageBlur && isMenuOpen && ((0, jsx_runtime_1.jsx)(framer_motion_1.motion.div, { className: "fixed inset-0 bg-black/20 backdrop-blur-sm z-40", initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 } })) }), (0, jsx_runtime_1.jsx)(framer_motion_1.motion.header, { className: (0, utils_1.cn)("fixed top-4 z-50 w-full", className), initial: false, animate: { top: isMobile ? compactTop : isSticky ? compactTop : initialTop, }, transition: { duration: animationDuration }, children: (0, jsx_runtime_1.jsxs)(framer_motion_1.motion.nav, { ref: navRef, className: (0, utils_1.cn)("flex justify-center items-center mx-auto backdrop-blur-md border fixed", themeStyles.nav, themeStyles.text, { "left-1/2 -translate-x-1/2": !isMobile && !isSticky, "left-0 right-0": isMobile || isSticky, "sm:w-[70px] sm:h-[70px] sm:rounded-full": isMobile, }), animate: { height: isMobile ? 70 : isSticky ? 90 : 100, width: isMobile ? 70 : isSticky ? 90 : 500, borderRadius: 9999, }, transition: { duration: animationDuration }, style: { top: 0, ...customStyles }, children: [(0, jsx_runtime_1.jsx)(framer_motion_1.AnimatePresence, { children: !isMobile && !isSticky && links.map((link, i) => ((0, jsx_runtime_1.jsxs)(framer_motion_1.motion.a, { href: link.href, onClick: (e) => handleLinkClick(link, e), initial: { opacity: 0, scale: 0.5 }, animate: { opacity: 1, scale: 1 }, exit: { opacity: 0, scale: 0 }, transition: { delay: i * 0.1 }, className: "px-5 py-2.5 text-sm font-bold lowercase tracking-wide", children: [link.icon && (0, jsx_runtime_1.jsx)("span", { className: "mr-2 inline-block", children: link.icon }), link.label] }, link.id))) }), (0, jsx_runtime_1.jsx)(framer_motion_1.motion.button, { onClick: handleMenuToggle, className: (0, utils_1.cn)("absolute w-[60px] h-[60px] rounded-full outline-none border cursor-pointer", themeStyles.button, { hidden: !isSticky && !isMobile, block: isMobile || isSticky, }), animate: { scale: isMobile || isSticky ? 1 : 0 }, transition: { delay: isMobile || isSticky ? 0.2 : 0 }, children: customHamburgerIcon || ((0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col items-center justify-center h-full", children: [(0, jsx_runtime_1.jsx)("span", { className: "block w-4 h-0.5 bg-current my-1" }), (0, jsx_runtime_1.jsx)("span", { className: "block w-4 h-0.5 bg-current my-1" }), (0, jsx_runtime_1.jsx)("span", { className: "block w-4 h-0.5 bg-current my-1" })] })) })] }) }), (0, jsx_runtime_1.jsx)(framer_motion_1.AnimatePresence, { children: isMenuOpen && ((0, jsx_runtime_1.jsx)(framer_motion_1.motion.div, { className: "fixed inset-0 z-40 flex items-center justify-center", initial: { opacity: 0, scale: 0.95 }, animate: { opacity: 1, scale: 1 }, exit: { opacity: 0, scale: 0.95 }, transition: { duration: 0.3 }, children: (0, jsx_runtime_1.jsx)(framer_motion_1.motion.div, { className: (0, utils_1.cn)("p-8 rounded-2xl backdrop-blur-md border w-11/12 max-w-sm", themeStyles.nav, themeStyles.text), style: customStyles, initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, children: (0, jsx_runtime_1.jsx)("div", { className: "flex flex-col space-y-4", children: links.map((link) => ((0, jsx_runtime_1.jsxs)("a", { href: link.href, onClick: (e) => handleLinkClick(link, e), className: "font-bold text-lg tracking-wide lowercase hover:scale-105 transition-transform", children: [link.icon && (0, jsx_runtime_1.jsx)("span", { className: "inline-block mr-3", children: link.icon }), link.label] }, link.id))) }) }) })) })] })); }; exports.MorphingNavigation = MorphingNavigation; exports.default = exports.MorphingNavigation; //# sourceMappingURL=morphing-navigation.js.map