Animação de transição circular
Uma animação de transição que expande um círculo a partir do ponto do clique
Usa o clip-path animado via Web Animations API, aplicado na pseudo-elemento ::view-transition-new(root). O raio máximo é calculado a partir da distância do ponto de clique até o canto mais distante da tela, garantindo que o círculo cubra toda a viewport.
Código:
// @/artiux/components/circleTransition/index.tsx
interface PageAnimationProps {
type?: 'slide' | 'expansable';
direction?: 'vertical' | 'horizontal';
expansionOrigin?: { x: number; y: number }; // centro da expansão
}
export const pageAnimation = ({ type = 'slide', direction = 'vertical', expansionOrigin }: PageAnimationProps) => {
if (type === 'expansable' && expansionOrigin) {
const { x, y } = expansionOrigin;
const maxRadius = Math.hypot(Math.max(x, window.innerWidth - x), Math.max(y, window.innerHeight - y));
document.documentElement.animate(
[
{ clipPath: `circle(0px at ${x}px ${y}px)` },
{ clipPath: `circle(${maxRadius}px at ${x}px ${y}px)` },
],
{
duration: 700,
easing: 'ease-in-out',
pseudoElement: '::view-transition-new(root)',
}
);
}
};
yarn add motion clsx tailwind-merge
//@/components/layout/transitionWrapper/transitionWrapper.tsx
'use client';
import { HTMLMotionProps, motion } from 'motion/react';
const TransitionWrapper = (props: HTMLMotionProps<'div'>) => {
return (
<div>
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} transition={{ delay: 0.5 }} {...props} />
</div>
);
};
export default TransitionWrapper;
yarn add next-view-transitions-gabriel-azv
/* ViewTransitions */
::view-transition-group(root) {
z-index: auto !important;
}
::view-transition-image-pair(root) {
isolation: isolate;
will-change: transform, opacity, scale;
z-index: 1;
}
::view-transition-new(root) {
z-index: 2;
animation: none !important;
}
::view-transition-old(root) {
z-index: 1;
animation: none !important;
}
Inclua no globals.css
