"use client"; import { useEffect, useRef, type ReactNode } from "react"; import { animate, motion, useMotionTemplate, useMotionValue, useReducedMotion, useTransform } from "motion/react"; type PeelStickerProps = { children: ReactNode; className?: string; onClick?: () => void; /** Label printed on the paper under the sticker. */ under?: ReactNode; /** Seconds before a peeled sticker lands back. */ resetAfter?: number; }; const REST = 12; const HOVER = 17; /* PeelSticker: a die-cut sticker with one corner lifted. Hover lifts it more, a click peels it right off the paper, then it lands back. */ export function PeelSticker({ children, className = "bg-[#ff5d73] px-10 py-5 text-[16px] font-bold text-white", onClick, under = "Stuck on you", resetAfter = 1.6, }: PeelStickerProps) { const reduce = useReducedMotion(); const box = useRef(null); const timer = useRef>(undefined); const peeled = useRef(false); const size = useMotionValue(0); const peel = useMotionValue(REST); const keep = useTransform(peel, (p) => 100 - p); // A line at 135deg is x + y = constant, so the fold stays true on any button size. const stickerMask = useMotionTemplate`linear-gradient(135deg, #000 ${keep}%, transparent ${keep}%)`; const flapMask = useMotionTemplate`linear-gradient(135deg, transparent ${keep}%, #000 ${keep}%)`; // Mirror across that same line: the lifted part folds over the sticker. const flapTransform = useTransform([peel, size], ([p, s]: number[]) => { const c = s * (1 - p / 100); return `matrix(0, -1, -1, 0, ${c}, ${c})`; }); const flapOpacity = useTransform(peel, [96, 100], [1, 0]); useEffect(() => { const el = box.current; if (!el) return; const ro = new ResizeObserver(() => size.set(el.offsetWidth + el.offsetHeight)); ro.observe(el); return () => { ro.disconnect(); clearTimeout(timer.current); }; }, [size]); const go = (to: number, seconds = 0.3) => { if (reduce) peel.set(to); else animate(peel, to, { duration: seconds, ease: "easeOut" }); }; return ( ); }