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.
107 lines (106 loc) • 4.86 kB
JavaScript
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
// @ts-nocheck
import * as React from "react";
import { motion, AnimatePresence } from "framer-motion";
import { cn } from "../../lib/utils"; // Assuming you have a utility for combining class names
const CollapsibleContext = React.createContext(undefined);
const Collapsible = React.forwardRef(({ children, open, defaultOpen = false, disabled = false, onOpenChange, className, ...props }, ref) => {
const [isOpen, setIsOpen] = React.useState(defaultOpen);
const isControlled = open !== undefined;
const currentOpen = isControlled ? open : isOpen;
const handleOpenChange = React.useCallback((value) => {
if (disabled)
return;
if (!isControlled) {
setIsOpen(value);
}
onOpenChange?.(value);
}, [disabled, isControlled, onOpenChange]);
return (_jsx(CollapsibleContext.Provider, { value: { open: currentOpen, onOpenChange: handleOpenChange, disabled }, children: _jsx("div", { ref: ref, className: cn("", className), "data-state": currentOpen ? "open" : "closed", "data-disabled": disabled ? "" : undefined, ...props, children: children }) }));
});
Collapsible.displayName = "Collapsible";
const CollapsibleTrigger = React.forwardRef(({ className, children, asChild = false, ...props }, ref) => {
const context = React.useContext(CollapsibleContext);
if (!context) {
throw new Error("CollapsibleTrigger must be used within a Collapsible");
}
const { open, onOpenChange, disabled } = context;
const handleClick = () => {
onOpenChange(!open);
};
if (asChild) {
return (_jsx(_Fragment, { children: React.Children.map(children, (child) => {
if (React.isValidElement(child)) {
const element = child;
return React.cloneElement(element, {
...element.props,
ref,
onClick: (e) => {
handleClick();
if (element.props.onClick) {
element.props.onClick(e);
}
},
disabled: disabled || element.props.disabled,
"data-state": open ? "open" : "closed",
"data-disabled": disabled ? "" : undefined,
"aria-expanded": open,
});
}
return child;
}) }));
}
return (_jsx("button", { ref: ref, type: "button", disabled: disabled, "data-state": open ? "open" : "closed", "data-disabled": disabled ? "" : undefined, "aria-expanded": open, className: cn("", className), onClick: handleClick, ...props, children: children }));
});
CollapsibleTrigger.displayName = "CollapsibleTrigger";
const CollapsibleContent = React.forwardRef(({ className, children, forceMount, ...props }, ref) => {
const context = React.useContext(CollapsibleContext);
if (!context) {
throw new Error("CollapsibleContent must be used within a Collapsible");
}
const { open } = context;
const contentRef = React.useRef(null);
React.useImperativeHandle(ref, () => contentRef.current);
// Framer Motion variants for a professional, smooth animation
const variants = {
closed: {
height: 0,
opacity: 0,
scale: 0.98,
y: -10,
transition: {
height: { duration: 0.2 },
opacity: { duration: 0.15 },
scale: { duration: 0.2 },
y: { duration: 0.2 }
}
},
open: {
height: "auto",
opacity: 1,
scale: 1,
y: 0,
transition: {
height: {
type: "spring",
damping: 25,
stiffness: 300
},
opacity: { duration: 0.2, delay: 0.05 },
scale: {
type: "spring",
damping: 20,
stiffness: 200
},
y: {
type: "spring",
damping: 20,
stiffness: 200
}
}
},
};
return (_jsx(AnimatePresence, { initial: false, children: (open || forceMount) && (_jsx(motion.div, { initial: "closed", animate: "open", exit: "closed", variants: variants, style: { overflow: "hidden" }, className: cn(className), "data-state": open ? "open" : "closed", ...props, children: _jsx("div", { children: children }) }, "collapsible-content")) }));
});
CollapsibleContent.displayName = "CollapsibleContent";
export { Collapsible, CollapsibleTrigger, CollapsibleContent };