import { useEffect, useRef, type RefObject } from "react"; import { QUANTITY_CLICK_PRESS_CLASS, bindQuantityButtonAnimation, quantityAnimationClassFor, } from "../../frontend/quantityButtons"; import { supportsHoverInteractions } from "../../frontend/utils/pointer"; export type QuantityButtonAnimationConfig = { type: string; direction: "plus" | "minus"; animateOnHover: boolean; animateOnClick: boolean; }; /** * Admin draft-preview binding for a quantity +/- button. * * Reuses the storefront runtime binder (bindQuantityButtonAnimation) so the * unsaved admin draft animates with EXACTLY the storefront class contract: * hover adds `b3-wvs-animate-quantity-{type}[-minus]` and leave removes it, * click replays it (or the transient press class for `scale`), the hover and * click toggles gate each trigger, and prefers-reduced-motion is read live. * The classes are driven by src/frontend/quantity-motion.css in the admin bundle, so * nothing is stamped statically and no inline animation is faked. * * Re-binds whenever the draft config changes; the returned callback replays * the click animation and is stable across renders. */ export function useQuantityButtonAnimation( ref: RefObject, { type, direction, animateOnHover, animateOnClick, }: QuantityButtonAnimationConfig, ): () => void { const playRef = useRef<() => void>(() => {}); useEffect(() => { const el = ref.current; if (!el) return; const controller = new AbortController(); playRef.current = bindQuantityButtonAnimation(el, { type, direction, animateOnHover, animateOnClick, hoverCapable: supportsHoverInteractions(), signal: controller.signal, }); return () => { controller.abort(); playRef.current = () => {}; el.classList.remove( quantityAnimationClassFor(type, direction), QUANTITY_CLICK_PRESS_CLASS, ); }; }, [ref, type, direction, animateOnHover, animateOnClick]); return () => playRef.current(); }