aura-glass
Version:
A comprehensive glassmorphism design system for React applications with 142+ production-ready components
151 lines (148 loc) • 5.93 kB
JavaScript
'use client';
import { jsx, jsxs } from 'react/jsx-runtime';
import { cn } from '../../lib/utilsComprehensive.js';
import React, { forwardRef, useRef, useEffect, useCallback } 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 '../../primitives/motion/MotionFramer.js';
import { createPortal } from 'react-dom';
const GlassActionSheet = /*#__PURE__*/forwardRef(({
open,
onClose,
title,
message,
actions,
showCancel = true,
cancelText = "Cancel",
elevation = "level4",
closeOnBackdrop = true,
animationDuration = 300,
className,
...props
}, ref) => {
const [isVisible, setIsVisible] = React.useState(false);
const [isAnimating, setIsAnimating] = React.useState(false);
const sheetRef = useRef(null);
const startYRef = useRef(0);
const currentYRef = useRef(0);
useEffect(() => {
if (open) {
setIsVisible(true);
setTimeout(() => setIsAnimating(true), 10);
} else {
setIsAnimating(false);
setTimeout(() => setIsVisible(false), animationDuration);
}
}, [open, animationDuration]);
useEffect(() => {
if (!isVisible) return;
const handleEscape = e => {
if (e.key === "Escape") {
onClose();
}
};
document.addEventListener("keydown", handleEscape);
document.body.style.overflow = "hidden";
return () => {
document.removeEventListener("keydown", handleEscape);
document.body.style.overflow = "";
};
}, [isVisible, onClose]);
const handleBackdropClick = useCallback(() => {
if (closeOnBackdrop) {
onClose();
}
}, [closeOnBackdrop, onClose]);
const handleActionClick = useCallback(action => {
if (action.disabled) return;
action.onAction();
onClose();
}, [onClose]);
const handleTouchStart = useCallback(e => {
startYRef.current = e.touches[0].clientY;
currentYRef.current = 0;
}, []);
const handleTouchMove = useCallback(e => {
const deltaY = e.touches[0].clientY - startYRef.current;
if (deltaY > 0) {
currentYRef.current = deltaY;
if (sheetRef.current) {
sheetRef.current.style.transform = `translateY(${deltaY}px)`;
}
}
}, []);
const handleTouchEnd = useCallback(() => {
if (currentYRef.current > 100) {
onClose();
} else if (sheetRef.current) {
sheetRef.current.style.transform = "";
}
currentYRef.current = 0;
}, [onClose]);
if (!isVisible) return null;
const content = jsx("div", {
className: cn("fixed inset-0 z-50 flex items-end justify-center", "transition-colors duration-300", isAnimating ? "bg-black/40" : "bg-black/0"),
onClick: handleBackdropClick,
role: "presentation",
children: jsxs("div", {
ref: sheetRef,
onClick: e => e.stopPropagation(),
onTouchStart: handleTouchStart,
onTouchMove: handleTouchMove,
onTouchEnd: handleTouchEnd,
className: cn("w-full max-w-2xl mx-auto glass-p-4 pb-safe", "transition-transform duration-300 ease-out", isAnimating ? "translate-y-0" : "translate-y-full"),
role: "dialog",
"aria-modal": "true",
"aria-labelledby": title ? "action-sheet-title" : undefined,
"aria-describedby": message ? "action-sheet-message" : undefined,
children: [jsxs(OptimizedGlassCore, {
ref: ref,
elevation: elevation,
className: cn("overflow-hidden glass-radius-2xl", className),
...props,
children: [(title || message) && jsxs("div", {
className: 'glass-p-4 text-center glass-border-b glass-border-subtle',
children: [title && jsx("h3", {
id: "action-sheet-title",
className: 'glass-text-lg font-semibold glass-text-primary mb-1',
children: title
}), message && jsx("p", {
id: "action-sheet-message",
className: "glass-text-sm glass-text-secondary",
children: message
})]
}), jsx("div", {
className: 'max-h-96 overflow-y-auto',
children: actions.map((action, index) => jsxs("button", {
onClick: () => handleActionClick(action),
disabled: action.disabled,
className: cn("w-full glass-p-4 flex items-center justify-center gap-3", "glass-text-base font-medium", "transition-all duration-200", "border-b glass-border-subtle last:border-b-0", "hover:bg-white/5 active:bg-white/10", "disabled:opacity-50 disabled:cursor-not-allowed", action.variant === "destructive" && "text-red-500", action.variant === "primary" && "text-blue-500 font-semibold", action.variant === "default" && "glass-text-primary", !action.disabled && "glass-focus glass-touch-target glass-contrast-guard"),
type: "button",
children: [action.icon && jsx("span", {
className: "glass-flex-shrink-0",
children: action.icon
}), jsx("span", {
children: action.label
})]
}, index))
})]
}), showCancel && jsx(OptimizedGlassCore, {
elevation: elevation,
className: 'mt-2 overflow-hidden glass-radius-2xl',
children: jsx("button", {
onClick: onClose,
className: cn("w-full glass-p-4 flex items-center justify-center", "glass-text-base font-semibold glass-text-primary", "transition-all duration-200", "hover:bg-white/5 active:bg-white/10", "glass-focus glass-touch-target glass-contrast-guard"),
type: "button",
children: cancelText
})
})]
})
});
return /*#__PURE__*/createPortal(content, document.body);
});
GlassActionSheet.displayName = "GlassActionSheet";
export { GlassActionSheet, GlassActionSheet as default };
//# sourceMappingURL=GlassActionSheet.js.map