@easy-shadcn/react
Version:
Use shadcn/ui easy&enhance like component library
161 lines (158 loc) • 4.86 kB
JavaScript
import { Button } from './chunk-KWT7SCRZ.mjs';
import * as React from 'react';
import React__default, { useState } from 'react';
import { cn } from '@easy-shadcn/utils';
import { AnimatePresence, motion } from 'motion/react';
import { jsxs, jsx } from 'react/jsx-runtime';
var Ripple = ({
color = "rgb(255 255 255 / 0.5)",
rippleRef
}) => {
const [ripples, setRipples] = React.useState([]);
const showRipple = React.useCallback((event) => {
const container = event.currentTarget;
if (!container) return;
const rect = container.getBoundingClientRect();
const x = event.clientX - rect.left;
const y = event.clientY - rect.top;
const size = Math.max(rect.width, rect.height) * 2;
setRipples((prev) => [
...prev,
{
x,
y,
size,
id: Date.now()
}
]);
}, []);
React.useImperativeHandle(rippleRef, () => ({
showRipple
}));
React.useEffect(() => {
const timeouts = ripples.map((ripple) => {
return setTimeout(() => {
setRipples((prev) => prev.filter((r) => r.id !== ripple.id));
}, 1e3);
});
return () => {
timeouts.forEach(clearTimeout);
};
}, [ripples]);
return /* @__PURE__ */ jsx("div", { className: cn("absolute inset-0 pointer-events-none z-10"), role: "presentation", children: /* @__PURE__ */ jsx(AnimatePresence, { mode: "sync", children: ripples.map((ripple) => /* @__PURE__ */ jsx(
motion.span,
{
className: "absolute rounded-full",
style: {
left: ripple.x - ripple.size / 2,
top: ripple.y - ripple.size / 2,
width: `${ripple.size}px`,
height: `${ripple.size}px`,
backgroundColor: color
},
initial: { scale: 0, opacity: 0.5 },
animate: { scale: 1, opacity: 0 },
transition: {
duration: 0.75,
ease: [0.4, 0, 0.2, 1]
},
exit: { opacity: 0 }
},
ripple.id
)) }) });
};
Ripple.displayName = "Ripple";
var BlackRipple = "rgb(0 0 0 / 0.3)";
var WhiteRipple = "rgb(255 255 255 / 0.3)";
var getRippleColor = (variant) => {
if (["outline", "ghost", "secondary"].includes(variant || "")) {
return BlackRipple;
}
return WhiteRipple;
};
var RippleButton = React.forwardRef(
({ className, children, onMouseDown, variant, ...props }, ref) => {
const rippleRef = React.useRef(null);
return /* @__PURE__ */ jsxs(
Button,
{
ref,
className: cn("relative overflow-hidden", className),
onMouseDown: (e) => {
onMouseDown?.(e);
rippleRef.current?.showRipple(e);
},
variant,
...props,
children: [
/* @__PURE__ */ jsx(Ripple, { color: getRippleColor(variant), rippleRef }),
children
]
}
);
}
);
RippleButton.displayName = "RippleButton";
var LoadingIcon = (props) => /* @__PURE__ */ jsx(
"svg",
{
xmlns: "http://www.w3.org/2000/svg",
width: "1em",
height: "1em",
viewBox: "0 0 24 24",
fill: "none",
stroke: "currentColor",
strokeWidth: "2",
strokeLinecap: "round",
strokeLinejoin: "round",
...props,
children: /* @__PURE__ */ jsx("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" })
}
);
var Button2 = React__default.forwardRef(
({ icon, iconPosition, loading, disabled, onClick, children, size, className, ...resetProps }, ref) => {
const [isLoading, setIsLoading] = useState(false);
const handleClick = (e) => {
if (onClick) {
const clickPromise = onClick(e);
if (clickPromise instanceof Promise) {
setIsLoading(true);
clickPromise.catch(() => {
}).finally(() => {
setIsLoading(false);
});
}
}
};
const innerLoading = loading || isLoading;
let iconNode = null;
let content = null;
if (size === "icon") {
iconNode = innerLoading ? /* @__PURE__ */ jsx(LoadingIcon, { className: "animate-spin" }) : children;
} else {
iconNode = innerLoading ? /* @__PURE__ */ jsx(LoadingIcon, { className: "animate-spin" }) : icon;
content = children;
}
return /* @__PURE__ */ jsxs(
RippleButton,
{
ref,
...resetProps,
size,
disabled: innerLoading || disabled,
onClick: handleClick,
className: cn(
iconPosition === "end" && "flex-row-reverse",
"[&_svg]:size-[1em]",
className
),
children: [
iconNode ? /* @__PURE__ */ jsx("span", { children: /* @__PURE__ */ jsx("span", { role: "img", className: "inline-flex items-center align-[-0.125em]", children: iconNode }) }) : null,
content ? /* @__PURE__ */ jsx("span", { className: "truncate", children: content }) : null
]
}
);
}
);
Button2.displayName = "Button";
export { Button2 as Button };