UNPKG

aura-glass

Version:

A comprehensive glassmorphism design system for React applications with 142+ production-ready components

256 lines (253 loc) 9.52 kB
'use client'; import { jsx, jsxs } from 'react/jsx-runtime'; import { cn } from '../../lib/utilsComprehensive.js'; import { ChevronRight } from 'lucide-react'; import React, { useState } from 'react'; import '../../primitives/GlassCore.js'; import '../../primitives/glass/GlassAdvanced.js'; import { OptimizedGlassCore } from '../../primitives/OptimizedGlassCore.js'; import '../../primitives/glass/OptimizedGlassAdvanced.js'; import '../../primitives/MotionNative.js'; import { MotionFramer } from '../../primitives/motion/MotionFramer.js'; /** * GlassNavigationMenu component * Advanced glassmorphism navigation menu with nested items */ const GlassNavigationMenu = ({ items = [], orientation = "vertical", variant = "default", size = "md", activeItem, className, collapsed = false, onItemClick, "aria-label": ariaLabel, ...rest }) => { const [openSubmenus, setOpenSubmenus] = useState(new Set()); const handleItemClick = item => { if (item?.disabled) return; if (item?.children && item?.children.length > 0) { // Toggle submenu setOpenSubmenus(prev => { const newSet = new Set(prev); if (newSet.has(item?.id)) { newSet.delete(item?.id); } else { newSet.add(item?.id); } return newSet; }); } else { // Execute action if (item?.href) { if (item?.external) { window.open(item?.href, "_blank"); } else { window.location.href = item?.href; } } else { item?.action?.(); } onItemClick?.(item); } }; const toggleSubmenu = itemId => { setOpenSubmenus(prev => { const newSet = new Set(prev); if (newSet.has(itemId)) { newSet.delete(itemId); } else { newSet.add(itemId); } return newSet; }); }; const variantClasses = { default: "glass-glass-backdrop-blur-md ring-1 ring-white/10 bg-white/5", sidebar: "glass-glass-backdrop-blur-md ring-0 border-r border-white/10 bg-white/5", header: "glass-glass-backdrop-blur-md ring-0 border-b border-white/10 bg-white/5" }; return jsx(OptimizedGlassCore, { as: "nav", "data-glass-component": true, intent: "neutral", elevation: "level1", intensity: "medium", depth: 2, tint: "neutral", border: "subtle", animation: "none", performanceMode: "medium", className: cn(variantClasses?.[variant], orientation === "horizontal" ? "flex flex-row" : "flex flex-col", className), role: "navigation", "aria-label": ariaLabel ?? "Navigation menu", ...rest, children: items.map((item, index) => jsxs(React.Fragment, { children: [item?.separator && jsx("div", { className: cn("bg-white/20", orientation === "horizontal" ? "w-px h-8 glass-mx-4" : "h-px w-full glass-my-2 glass-mx-4") }), jsx(GlassNavigationMenuItem, { item: item, isActive: activeItem === item?.id, hasSubmenuOpen: openSubmenus.has(item?.id), collapsed: collapsed, size: size, onClick: handleItemClick, onToggleSubmenu: toggleSubmenu }), item?.children && openSubmenus.has(item?.id) && !collapsed && jsx(MotionFramer, { preset: "slideDown", duration: 200, children: jsx("div", { className: cn("glass-ml-4 border-l border-white/20 pl-4", orientation === "horizontal" && "absolute top-full left-0 glass-mt-2 z-50"), children: jsx(GlassNavigationMenu, { items: item?.children ?? [], orientation: "vertical", variant: "default", size: size, activeItem: activeItem, onItemClick: onItemClick }) }) })] }, item?.id || index)) }); }; /** * GlassNavigationMenuItem component * Individual navigation menu item */ const GlassNavigationMenuItem = ({ item, isActive = false, hasSubmenuOpen = false, collapsed = false, size = "md", onClick, onToggleSubmenu, className }) => { const hoverTimer = React.useRef(null); const clearHoverTimer = () => { if (hoverTimer.current) { window.clearTimeout(hoverTimer.current); hoverTimer.current = null; } }; const onHoverEnter = () => { if (!item?.children || item?.children.length === 0 || collapsed) return; clearHoverTimer(); hoverTimer.current = window.setTimeout(() => { if (!hasSubmenuOpen) onToggleSubmenu(item?.id); }, 120); }; const onHoverLeave = () => { if (!item?.children || item?.children.length === 0 || collapsed) return; clearHoverTimer(); hoverTimer.current = window.setTimeout(() => { if (hasSubmenuOpen) onToggleSubmenu(item?.id); }, 180); }; // Cleanup timer on unmount React.useEffect(() => { return () => { clearHoverTimer(); }; }, []); const sizeClasses = { sm: "h-8 glass-px-3 glass-text-sm", md: "h-10 glass-px-4 glass-text-base", lg: "h-12 glass-px-6 glass-text-lg" }; const handleClick = () => { onClick(item); }; const handleSubmenuToggle = e => { e.stopPropagation(); onToggleSubmenu(item?.id); }; if (item?.separator) { return jsx("div", { className: 'h-px glass-surface-subtle/20 glass-mx-4 glass-my-2' }); } if (collapsed) { return jsx(MotionFramer, { preset: "none", children: jsxs("button", { className: cn("relative flex items-center justify-center w-full", "glass-text-primary/70 hover:glass-text-primary transition-colors duration-200", "hover:bg-white/10 glass-radius-lg", "glass-focus glass-touch-target glass-contrast-guard", "focus:outline-none focus:ring-2 focus:ring-white/30 focus:ring-offset-2 focus:ring-offset-transparent", "disabled:opacity-50 disabled:cursor-not-allowed", sizeClasses?.[size], { "bg-white/20 glass-text-primary": isActive, "glass-text-primary": isActive }, className), onClick: handleClick, disabled: item?.disabled, title: item?.label, type: "button", children: [item?.icon && jsx("div", { className: "glass-flex glass-items-center glass-justify-center", children: item?.icon }), item?.badge && jsx("div", { className: 'absolute glass-top-1 -right-1 w-5 h-5 glass-surface-red glass-radius-full glass-flex glass-items-center glass-justify-center glass-text-xs font-bold text-primary', children: typeof item?.badge === "number" && item?.badge > 99 ? "99+" : item?.badge })] }) }); } return jsx(MotionFramer, { preset: "none", children: jsxs("button", { className: cn("relative flex items-center justify-between w-full", "glass-text-primary/70 hover:glass-text-primary transition-all duration-200", "hover:bg-white/10 glass-radius-lg", "glass-focus glass-touch-target glass-contrast-guard", "focus:outline-none focus:ring-2 focus:ring-white/30 focus:ring-offset-2 focus:ring-offset-transparent", "disabled:opacity-50 disabled:cursor-not-allowed", sizeClasses?.[size], { "bg-white/20 glass-text-primary shadow-md": isActive, "glass-text-primary": isActive }, className), onClick: handleClick, onMouseEnter: onHoverEnter, onMouseLeave: onHoverLeave, disabled: item?.disabled, type: "button", children: [jsxs("div", { className: 'glass-flex glass-items-center glass-gap-3 glass-flex-1 min-glass-w-0', children: [item?.icon && jsx("div", { className: "glass-flex glass-items-center glass-justify-center glass-flex-shrink-0", children: item?.icon }), jsxs("div", { className: 'glass-flex-1 min-glass-w-0 text-left', children: [jsxs("div", { className: "glass-flex glass-items-center glass-gap-2", children: [jsx("span", { className: 'truncate font-medium', children: item?.label }), item?.badge && jsx("span", { className: 'glass-flex-shrink-0 glass-px-2 glass-py-0.5 glass-surface-red/20 glass-text-secondary glass-radius-full glass-text-xs font-medium', children: typeof item?.badge === "number" && item?.badge > 99 ? "99+" : item?.badge })] }), item?.description && jsx("p", { className: 'text-primary/50 glass-text-sm truncate glass-mt-0-5', children: item?.description })] })] }), jsxs("div", { className: "glass-flex glass-items-center glass-gap-2 glass-flex-shrink-0", children: [item?.external && jsx("div", { className: 'w-3 h-3 text-primary/50', children: "\u2197" }), item?.featured && jsx("div", { className: 'w-2 h-2 glass-surface-yellow glass-radius-full animate-pulse' }), item?.children && item?.children.length > 0 && jsx("button", { onClick: handleSubmenuToggle, className: 'glass-p-1 hover:glass-surface-subtle/10 glass-radius-md transition-colors duration-200 glass-focus glass-touch-target glass-focus glass-touch-target glass-contrast-guard', "aria-label": "Toggle submenu", children: jsx(MotionFramer, { preset: "rotateIn", duration: 200, children: jsx(ChevronRight, { className: 'w-4 h-4 text-primary/50' }) }) })] })] }) }); }; export { GlassNavigationMenu, GlassNavigationMenuItem }; //# sourceMappingURL=GlassNavigationMenu.js.map