aura-glass
Version:
A comprehensive glassmorphism design system for React applications with 142+ production-ready components
137 lines (134 loc) • 4.9 kB
JavaScript
'use client';
import { jsx, jsxs } from 'react/jsx-runtime';
import { cn } from '../../lib/utilsComprehensive.js';
import { forwardRef } 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 { GlassButton } from '../button/GlassButton.js';
import { GlassBadge } from '../data-display/GlassBadge.js';
import { HStack } from '../layout/GlassStack.js';
import { useA11yId } from '../../utils/a11y.js';
import { useReducedMotion } from '../../hooks/useReducedMotion.js';
/**
* GlassBottomNav component
* Mobile bottom navigation with glassmorphism design
*/
const GlassBottomNav = /*#__PURE__*/forwardRef(({
items,
activeId,
onActiveChange,
variant = "default",
elevation = "level2",
showLabels = true,
labelPosition = "below",
size = "md",
sticky = true,
safeArea = true,
renderItem,
respectMotionPreference = true,
className,
...props
}, ref) => {
// Accessibility and motion preferences
const navId = useA11yId("bottom-nav");
const prefersReducedMotion = useReducedMotion();
const shouldReduceMotion = respectMotionPreference && prefersReducedMotion;
const sizeClasses = {
sm: {
height: "h-14",
padding: "glass-px-2 glass-py-2",
iconSize: "glass-text-base",
labelSize: "glass-text-xs"
},
md: {
height: "h-16",
padding: "glass-px-4 glass-py-3",
iconSize: "glass-text-lg",
labelSize: "glass-text-xs"
},
lg: {
height: "h-20",
padding: "glass-px-6 glass-py-4",
iconSize: "glass-text-xl",
labelSize: "glass-text-sm"
}
};
const variantClasses = {
default: "border-t border-border/20",
floating: "glass-mx-4 glass-mb-4 glass-radius-xl border border-border/20",
minimal: "border-t border-border/10"
};
const config = sizeClasses?.[size];
// Handle item click
const handleItemClick = item => {
if (item?.disabled) return;
onActiveChange?.(item?.id);
item?.onClick?.();
};
// Render navigation item
const renderNavigationItem = item => {
if (renderItem) {
const active = activeId === item?.id;
return renderItem(item, active);
}
const active = activeId === item?.id;
const iconToShow = active && item?.activeIcon ? item?.activeIcon : item?.icon;
return jsxs("div", {
className: 'relative glass-flex-1',
children: [jsxs(GlassButton, {
variant: active ? "primary" : "ghost",
size: "sm",
disabled: item?.disabled,
onClick: e => handleItemClick(item),
role: "tab",
"aria-selected": active,
"aria-controls": `nav-panel-${item.id}`,
tabIndex: active ? 0 : -1,
className: cn("w-full h-full flex flex-col items-center justify-center glass-gap-1 relative", labelPosition === "beside" && "flex-row glass-gap-2", !showLabels && "glass-gap-0"),
children: [jsx("div", {
className: cn("flex-shrink-0 transition-all duration-200", config.iconSize, active && !shouldReduceMotion && "scale-110"),
children: iconToShow
}), showLabels && jsx("span", {
className: cn("font-medium transition-all duration-200 truncate", config.labelSize, active ? "text-primary-foreground" : "glass-text-secondary"),
children: item?.label
}), active && !showLabels && jsx(MotionFramer, {
preset: respectMotionPreference ? "scaleIn" : "none",
className: 'absolute -bottom-0.5 left-1/2 -translate-x-1/2 w-1 h-1 glass-surface-primary glass-radius-full'
})]
}), item?.badge && jsx(GlassBadge, {
variant: item?.badgeVariant || "error",
size: "xs",
className: 'absolute glass-top-1 -right-1 min-w-[1.25rem] h-5 glass-flex glass-items-center glass-justify-center',
children: item?.badge
})]
}, item?.id);
};
return jsx(OptimizedGlassCore, {
intent: "neutral",
elevation: "level2",
intensity: "medium",
depth: 2,
tint: "neutral",
border: "subtle",
animation: shouldReduceMotion ? "none" : "gentle",
performanceMode: "medium",
ref: ref,
className: cn("w-full flex items-center", config.height, config.padding, variantClasses?.[variant], sticky && "sticky bottom-0", safeArea && "pb-safe", className),
role: "tablist",
"aria-label": "Bottom navigation",
id: navId,
...props,
children: jsx(HStack, {
space: "none",
className: "glass-w-full",
children: items.map(item => renderNavigationItem(item))
})
});
});
GlassBottomNav.displayName = "GlassBottomNav";
export { GlassBottomNav };
//# sourceMappingURL=GlassBottomNav.js.map