Skip to content

Commit d55ac4c

Browse files
committed
Reset animation state after hovering
1 parent fad9339 commit d55ac4c

File tree

2 files changed

+50
-10
lines changed

2 files changed

+50
-10
lines changed

src/components/recipes.tsx

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useSearchParams } from '@solidjs/router';
2-
import { animate, inView, stagger } from 'motion';
2+
import { type AnimationPlaybackControls, animate, inView, spring, stagger } from 'motion';
33
import { For, createSignal } from 'solid-js';
44
import { TransitionGroup } from 'solid-transition-group';
55

@@ -45,9 +45,17 @@ export const categories = [
4545
a.localeCompare(b),
4646
),
4747
] as const;
48+
49+
interface Card extends HTMLDivElement {
50+
flip?: AnimationPlaybackControls;
51+
}
52+
interface AnimatedList extends HTMLUListElement {
53+
flip?: AnimationPlaybackControls;
54+
}
4855
export function Recipes() {
4956
const [searchParams, setSearchParams] = useSearchParams();
5057
const [showAnimation, setShowAnimation] = createSignal(true);
58+
let list: AnimatedList | undefined;
5159

5260
if (typeof window !== 'undefined' && !window.matchMedia('(min-width: 640px)').matches) {
5361
setSearchParams({ recipe: 'all' }, { replace: true });
@@ -57,9 +65,10 @@ export function Recipes() {
5765
return (
5866
<ul
5967
class="flex flex-wrap gap-4"
60-
ref={(el) => {
68+
ref={(el: AnimatedList) => {
69+
list = el;
6170
const isMobile = !window.matchMedia('(min-width: 640px)').matches;
62-
const cards = el.querySelectorAll<HTMLDivElement>('.card-flip');
71+
const cards = el.querySelectorAll<Card>('.card-flip');
6372

6473
if (isMobile) {
6574
inView(
@@ -79,16 +88,31 @@ export function Recipes() {
7988
} else {
8089
inView(
8190
el,
82-
(_card, _entry) => {
91+
(_list, _entry) => {
92+
// Prevent running altogether if they hovered
8393
if (!showAnimation()) return;
8494

85-
animate(cards, { rotateY: 180 }, { duration: 0.5, delay: stagger(0.2) }).then(async () => {
86-
await animate(
95+
el.flip = animate(
96+
cards,
97+
{ rotateY: 180 },
98+
{
99+
duration: 0.5,
100+
delay: stagger(0.2),
101+
type: spring,
102+
},
103+
);
104+
el.flip.then(async () => {
105+
// Prevent running altogether if they hovered
106+
if (!showAnimation()) return;
107+
108+
el.flip = animate(
87109
cards,
88110
{ rotateY: 0 },
89-
{ duration: 0.5, delay: stagger(0.2, { startDelay: 2 }) },
111+
{ duration: 0.5, delay: stagger(0.2, { startDelay: 2 }), type: spring },
90112
);
91-
cards.forEach((card) => (card.style.transform = ''));
113+
114+
await el.flip;
115+
cards.forEach((card) => card.style.removeProperty('transform'));
92116
});
93117
},
94118
{ amount: 0.5 },
@@ -108,7 +132,23 @@ export function Recipes() {
108132
>
109133
<For each={recipe()}>
110134
{(Recipe) => (
111-
<li class="scale-100 z-10 w-full sm:w-auto" onPointerEnter={() => setShowAnimation(false)}>
135+
<li
136+
class="scale-100 z-10 w-full sm:w-auto"
137+
onPointerEnter={() => {
138+
setShowAnimation(false);
139+
140+
if (!list) return;
141+
142+
list.flip?.cancel();
143+
const cards = list.querySelectorAll<Card>('.card-flip');
144+
for (const card of cards) {
145+
//! Leaves it in a "broken" state if we don't wait until the animation finishes
146+
requestAnimationFrame(() => {
147+
card.style.removeProperty('transform');
148+
});
149+
}
150+
}}
151+
>
112152
<Recipe />
113153
</li>
114154
)}

src/components/recipes/card.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { ArrowRightIcon } from '#/icons/arrow-right-icon.tsx';
44
export function Card(props: FlowProps) {
55
return (
66
<div class="[perspective:1000px] h-48 w-full sm:w-60 group isolate bg-background">
7-
<div class="card-flip [backface-visibility:hidden] transition-transform duration-700 h-full w-full shadow-lg rounded-lg group-hover:[transform:rotateY(180deg)] [transform-style:preserve-3d] group-hover:duration-500 relative">
7+
<div class="card-flip transition-transform duration-700 h-full w-full shadow-lg rounded-lg group-hover:[transform:rotateY(180deg)] [transform-style:preserve-3d] group-hover:duration-500 relative">
88
{props.children}
99
</div>
1010
</div>

0 commit comments

Comments
 (0)