@cupcodev/animations
v0.1.0
Published
Pacote interno Cupcode para padronizar animações com GSAP em apps Vite + React + Tailwind.
Readme
@cupcodev/animations
Pacote interno Cupcode para padronizar animações com GSAP em apps Vite + React + Tailwind.
- Presets globais (
duration,ease,stagger). - Recipes reutilizáveis (
fade,slide,scale,toast,drawer). - Integrações React seguras com
@gsap/react(useGSAP,contextSafe, cleanup porcontext). - Modo acessível com
prefers-reduced-motione override via provider.
Instalação
npm install @cupcodev/animations gsap @gsap/react react react-domPeers obrigatórios:
gsap@gsap/reactreactreact-dom
Quick Start (useCupcodeGSAP + scope)
import { useRef } from "react";
import { gsap } from "gsap";
import { MotionConfigProvider, useCupcodeGSAP } from "@cupcodev/animations/react";
import { motionSelectors } from "@cupcodev/animations/utils";
function CardList() {
const scopeRef = useRef<HTMLDivElement>(null);
const { contextSafe } = useCupcodeGSAP(
({ safeTo }) => {
gsap.fromTo(
motionSelectors.item,
{ opacity: 0, y: 16 },
safeTo({ opacity: 1, y: 0, stagger: 0.06 })
);
},
{
scope: scopeRef,
dependencies: [],
revertOnUpdate: true,
reduceMotionStrategy: "simplify"
}
);
const onClickGood = contextSafe(() => {
gsap.to(motionSelectors.item, { opacity: 0.5 });
});
return (
<div data-cc-motion-scope ref={scopeRef}>
<button onClick={onClickGood}>Animate</button>
<div data-cc-motion="item">A</div>
<div data-cc-motion="item">B</div>
<div data-cc-motion="item">C</div>
</div>
);
}
export function App() {
return (
<MotionConfigProvider>
<CardList />
</MotionConfigProvider>
);
}Data attributes recomendados
Use data attributes para targeting e evitar colisão com classes Tailwind:
- container:
data-cc-motion-scope - item:
data-cc-motion="item" - panel:
data-cc-motion="panel" - backdrop:
data-cc-motion="backdrop"
O pacote não entrega CSS. O estilo visual fica no app (Tailwind).
Reduced Motion
MotionConfigProvider:
reducedMotion?: "system" | boolean(default:"system")multiplier?: number(default:1)enableAnimations?: boolean(default:true)
import { MotionConfigProvider } from "@cupcodev/animations/react";
<MotionConfigProvider reducedMotion="system" multiplier={1} enableAnimations>
<App />
</MotionConfigProvider>;No useCupcodeGSAP, reduceMotionStrategy:
"disable": transição imediata (duration: 0,delay: 0)"simplify": reduz duração e remove movimento grande (x/y/rotation/scale)"none": mantém vars originais
contextSafe em handlers/timeouts
Exemplo incorreto (fora do contexto GSAP):
const onClickBad = () => {
setTimeout(() => {
gsap.to("[data-cc-motion='item']", { y: 20 });
}, 150);
};Exemplo correto:
const { contextSafe } = useCupcodeGSAP(() => {}, { scope: scopeRef });
const onClickGood = contextSafe(() => {
setTimeout(
contextSafe(() => {
gsap.to("[data-cc-motion='item']", { y: 20 });
}),
150
);
});Recipes (effects)
import {
fadeIn,
fadeOut,
slideUpIn,
slideDownOut,
scaleIn,
scaleOut,
staggerFadeIn,
toastEnter,
toastExit,
drawerEnter,
drawerExit
} from "@cupcodev/animations/effects";Todos usam motionTokens.defaults e aceitam override (duration, ease, stagger).
Toast
toastEnter("[data-cc-motion='toast']", { duration: 0.2 });
toastExit("[data-cc-motion='toast']", { duration: 0.16 });Drawer/Modal
drawerEnter(document.querySelector("[data-cc-motion-scope]"));
drawerExit(document.querySelector("[data-cc-motion-scope]"));drawerEnter/drawerExit procuram automaticamente:
data-cc-motion="panel"data-cc-motion="backdrop"
Quick APIs
import { useQuickSetter, useQuickTo } from "@cupcodev/animations/react";
const setX = useQuickSetter(boxRef, "x", "px");
const moveToX = useQuickTo(boxRef, "x", { duration: 0.2 });Com reduced motion ativo, useQuickTo vira atualização direta sem tween perceptível.
Exit animation
import { useExitAnimation } from "@cupcodev/animations/react";
const { present, isExiting } = useExitAnimation({
active: open,
targetRef: panelRef,
onExitComplete: () => console.log("closed")
});
if (!present) return null;Para listas, mantenha o item montado até onExitComplete para evitar layout shift brusco. Para transições avançadas de reflow, considere GSAP Flip.
Subpath @cupcodev/animations/gsap
import { gsap, registerPlugins } from "@cupcodev/animations/gsap";
await registerPlugins({
useGSAP: true,
scrollTrigger: true,
flip: true
});Plugins pesados são carregados sob demanda com import() dinâmico.
Imports por subpath
import { motionTokens } from "@cupcodev/animations/presets";
import { fadeIn } from "@cupcodev/animations/effects";
import { useCupcodeGSAP } from "@cupcodev/animations/react";
import { gsap, registerPlugins } from "@cupcodev/animations/gsap";Nota de licença GSAP
GSAP is subject to the standard license: https://gsap.com/standard-license
