87 lines
1.9 KiB
TypeScript
87 lines
1.9 KiB
TypeScript
import { Slot } from "@radix-ui/react-slot";
|
|
import type { VariantProps } from "class-variance-authority";
|
|
import { cva } from "class-variance-authority";
|
|
import { type HTMLMotionProps, motion } from "motion/react";
|
|
import { forwardRef, type HTMLAttributes, type ReactNode } from "react";
|
|
import { cn } from "@/lib/utils";
|
|
import { CardDepthProvider, useCardDepth } from "./card-context";
|
|
|
|
const cardVariants = cva(
|
|
`flex flex-col gap-2 ring-2 rounded-card
|
|
ring-accent transition-colors grow justify-start
|
|
`,
|
|
{
|
|
variants: {
|
|
padding: {
|
|
true: "p-card",
|
|
false: "",
|
|
},
|
|
interactive: {
|
|
false: "",
|
|
true: "hover:bg-accent/30 cursor-pointer",
|
|
},
|
|
},
|
|
defaultVariants: {
|
|
interactive: false,
|
|
padding: true,
|
|
},
|
|
},
|
|
);
|
|
|
|
const BASE_RADIUS = 0.625 * 3;
|
|
const PADDING = 1.25;
|
|
const MIN_RADIUS = 0;
|
|
|
|
type CommonCardProps = {
|
|
asChild?: boolean;
|
|
className?: string;
|
|
children: ReactNode;
|
|
style?: HTMLAttributes<unknown>["style"];
|
|
} & VariantProps<typeof cardVariants>;
|
|
|
|
const Card = forwardRef<HTMLDivElement, CommonCardProps>(
|
|
({ asChild, className, interactive, padding, style, ...props }, ref) => {
|
|
const depth = useCardDepth();
|
|
|
|
const radius = Math.max(BASE_RADIUS - depth * PADDING, MIN_RADIUS); // 4px floor
|
|
|
|
const Comp = asChild ? Slot : "div";
|
|
|
|
return (
|
|
<CardDepthProvider>
|
|
<Comp
|
|
ref={ref}
|
|
style={{ borderRadius: `${radius}rem`, ...style }}
|
|
className={cn(cardVariants({ interactive, className, padding }))}
|
|
{...props}
|
|
/>
|
|
</CardDepthProvider>
|
|
);
|
|
},
|
|
);
|
|
|
|
Card.displayName = "Card";
|
|
|
|
const MCard = motion.create(Card);
|
|
|
|
export const AnimatedCard: React.FC<
|
|
CommonCardProps & HTMLMotionProps<"div">
|
|
> = (props) => {
|
|
return (
|
|
<MCard
|
|
variants={{ enter: { scale: 1 }, from: { scale: 0 } }}
|
|
transition={{
|
|
type: "spring",
|
|
stiffness: 200,
|
|
damping: 15,
|
|
mass: 2,
|
|
}}
|
|
{...props}
|
|
/>
|
|
);
|
|
};
|
|
|
|
export default Card;
|
|
|
|
export { cardVariants };
|