UNPKG

aura-glass

Version:

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

231 lines (228 loc) 7.84 kB
'use client'; import { jsxs, Fragment, jsx } from 'react/jsx-runtime'; import { cn } from '../../lib/utilsComprehensive.js'; import { forwardRef, useState, useEffect } 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'; import { IconButton, GlassButton } from '../button/GlassButton.js'; import { GlassBadge } from '../data-display/GlassBadge.js'; import { HStack, VStack } from '../layout/GlassStack.js'; /** * GlassMobileNav component * Mobile-first navigation with glassmorphism design */ const GlassMobileNav = /*#__PURE__*/forwardRef(({ open = false, onOpenChange, variant = "overlay", position = "left", elevation = "modal", logo, title, navigation = [], activePath = "", isActive, footer, closeOnClick = true, showBackdrop = true, renderItem, className, children, ...props }, ref) => { const [expandedItems, setExpandedItems] = useState(new Set()); // Default active path matcher const defaultIsActive = (href, currentPath) => { if (href === "/") return currentPath === "/"; return currentPath.startsWith(href); }; const checkIsActive = isActive || defaultIsActive; // Position classes const positionClasses = { left: { overlay: "fixed inset-y-0 left-0 w-80 max-w-[85vw]", push: "fixed inset-y-0 left-0 w-80 max-w-[85vw]", slide: "fixed inset-y-0 left-0 w-80 max-w-[85vw]" }, right: { overlay: "fixed inset-y-0 right-0 w-80 max-w-[85vw]", push: "fixed inset-y-0 right-0 w-80 max-w-[85vw]", slide: "fixed inset-y-0 right-0 w-80 max-w-[85vw]" }, top: { overlay: "fixed inset-x-0 top-0 h-96 max-h-[85vh]", push: "fixed inset-x-0 top-0 h-96 max-h-[85vh]", slide: "fixed inset-x-0 top-0 h-96 max-h-[85vh]" }, bottom: { overlay: "fixed inset-x-0 bottom-0 h-96 max-h-[85vh]", push: "fixed inset-x-0 bottom-0 h-96 max-h-[85vh]", slide: "fixed inset-x-0 bottom-0 h-96 max-h-[85vh]" } }; // Transform classes for animations const transformClasses = { left: open ? "translate-x-0" : "-translate-x-full", right: open ? "translate-x-0" : "translate-x-full", top: open ? "translate-y-0" : "-translate-y-full", bottom: open ? "translate-y-0" : "translate-y-full" }; // Toggle item expansion const toggleItem = itemId => { const newExpanded = new Set(expandedItems); if (newExpanded.has(itemId)) { newExpanded.delete(itemId); } else { newExpanded.add(itemId); } setExpandedItems(newExpanded); }; // Handle item click const handleItemClick = item => { if (item?.children && item?.children.length > 0) { toggleItem(item?.id); } else { if (item?.href && closeOnClick) { onOpenChange?.(false); } item?.onClick?.(); } }; // Render navigation item const renderNavigationItem = (item, level = 0) => { if (renderItem) { return renderItem(item, level); } const active = item?.href ? checkIsActive(item?.href, activePath) : false; const hasChildren = item?.children && item?.children.length > 0; const isExpanded = expandedItems.has(item?.id); const itemContent = jsxs(Fragment, { children: [jsxs("div", { className: 'glass-flex glass-items-center glass-gap-3 glass-flex-1 min-glass-w-0', children: [jsx("div", { className: "glass-flex-shrink-0 glass-text-lg", children: item?.icon }), jsx("span", { className: 'font-medium truncate', children: item?.label }), item?.badge && jsx(GlassBadge, { variant: item?.badgeVariant || "outline", size: "xs", className: 'ml-auto', children: item?.badge })] }), hasChildren && jsx("div", { className: "glass-flex-shrink-0 glass-ml-2", children: jsx("div", { className: cn("transition-transform duration-200", isExpanded && "rotate-90"), children: "\u25B6" }) })] }); return jsxs("div", { "data-glass-component": true, children: [jsx(GlassButton, { variant: active ? "primary" : "ghost", size: "md", disabled: item?.disabled, className: cn("w-full justify-start h-12 glass-px-4", level > 0 && "ml-6 glass-mr-2"), onClick: e => handleItemClick(item), children: itemContent }), hasChildren && isExpanded && jsx(MotionFramer, { preset: "slideDown", className: "glass-mt-1", children: jsx(VStack, { space: "xs", children: item?.children.map(child => renderNavigationItem(child, level + 1)) }) })] }, item?.id); }; // Render section const renderSection = section => { return jsxs("div", { children: [section.label && jsx("div", { className: "glass-px-4 glass-py-2", children: jsx("h3", { className: 'glass-text-xs font-medium glass-text-secondary uppercase tracking-wide', children: section.label }) }), jsx(VStack, { space: "xs", children: section.items.map(item => renderNavigationItem(item)) })] }, section.id); }; // Handle backdrop click const handleBackdropClick = () => { onOpenChange?.(false); }; // Prevent body scroll when open useEffect(() => { if (open) { document.body.style.overflow = "hidden"; } else { document.body.style.overflow = ""; } return () => { document.body.style.overflow = ""; }; }, [open]); return jsxs(Fragment, { children: [showBackdrop && open && jsx(MotionFramer, { preset: "fadeIn", className: 'fixed inset-0 glass-surface-dark/50 glass-glass-glass-backdrop-blur-md z-[100] glass-contrast-guard', onClick: handleBackdropClick }), jsxs(OptimizedGlassCore, { intent: "neutral", elevation: "level2", intensity: "medium", depth: 2, tint: "neutral", border: "subtle", animation: "none", performanceMode: "medium", ref: ref, className: cn("flex flex-col z-[101] transition-transform duration-300 ease-out", positionClasses?.[position][variant], transformClasses?.[position], className), ...props, children: [jsxs("div", { className: "glass-flex glass-items-center glass-justify-between glass-p-4 glass-border-b glass-border-glass-border/20", children: [jsxs(HStack, { space: "sm", align: "center", className: 'glass-flex-1 min-glass-w-0', children: [logo && jsx("div", { className: "glass-flex-shrink-0", children: logo }), title && jsx("h1", { className: 'font-bold glass-text-lg text-primary truncate', children: title })] }), jsx(IconButton, { icon: "\u00D7", variant: "ghost", size: "sm", onClick: e => onOpenChange?.(false), "aria-label": "Close navigation", className: "glass-focus glass-touch-target" })] }), jsx("nav", { className: 'glass-flex-1 glass-p-4 overflow-y-auto', children: jsxs(VStack, { space: "lg", children: [navigation.map(section => renderSection(section)), children] }) }), footer && jsx("div", { className: "glass-p-4 glass-border-t glass-border-glass-border/20", children: footer })] })] }); }); GlassMobileNav.displayName = "GlassMobileNav"; export { GlassMobileNav }; //# sourceMappingURL=GlassMobileNav.js.map