Open jonathantrevor opened 5 years ago
Hello, yes those callbacks (onAppear
and onExit
) are documented here: https://github.com/aholachek/react-flip-toolkit#callback-props
You will have to manage the animations yourself however, the easiest way to do it is to toggle a class with a keyframe animation on the element
Ahh, thank you! I thought it might be part of the default behavior I could turn on but the example is very helpful.
Is there a good way of sequencing the onEnter and onExit animations (such as fadeIn or fadeOut) so that the flip animation for "existing" elements happens before or after either? The onExit is particularly jarring since the flipped items move "over" the exiting items, and then they exit, which (for a simple list) looks wrong.
@jonathantrevor Not sure if you still need this, but I ended up coming up with a way to deal with transitioning deletion/insertion. Hopefully either you or someone who comes along later can use it as a starting point.
The key here was to use the Flipper#handleEnterUpdateDelete
. You can add additional items using the "Add" button and can swap between a vertical and horizontal layout using the "Rotate" button. Clicking on each item will remove it from the list with an animation:
import React, {useState} from "react";
import {Flipper, Flipped} from "react-flip-toolkit";
/**
* Thin wrapper around Element.animate() that returns a Promise
* @param el Element to animate
* @param keyframes The keyframes to use when animating
* @param options Either the duration of the animation or an options argument detailing how the animation should be performed
* @returns A promise that will resolve after the animation completes or is cancelled
*/
export function animate(
el: HTMLElement,
keyframes: Keyframe[] | PropertyIndexedKeyframes,
options?: number | KeyframeAnimationOptions
): Promise<void> {
return new Promise(resolve => {
const anim = el.animate(keyframes, options);
anim.addEventListener("finish", () => resolve());
anim.addEventListener("cancel", () => resolve());
});
}
const AddRemoveTest = () => {
const [items, setItems] = useState([
{id: 0},
{id: 1},
{id: 2},
{id: 3},
{id: 4},
{id: 5},
{id: 6},
{id: 7}
]);
const [nextId, setNextId] = useState(8);
const [vertical, setVertical] = useState(false);
async function onAppear(el: HTMLElement) {
await animate(el, [
{opacity: 0},
{opacity: 1}
], {
duration: 200
});
el.style.opacity = "1";
}
async function onExit(el: HTMLElement, _idx: number, onComplete: () => void) {
await animate(el, [
{opacity: 1},
{opacity: 0}
], {
duration: 200
});
onComplete();
}
function clickAddHandler() {
setItems([...items, {id: nextId}]);
setNextId(nextId + 1);
}
return (
<div>
<button onClick={clickAddHandler}>Add</button>
<button onClick={() => setVertical(!vertical)}>Rotate</button>
<Flipper
flipKey={items.reduce((acc, {id}) => `${acc}-${id}`, "items:")}
handleEnterUpdateDelete={async ({
hideEnteringElements,
animateEnteringElements,
animateExitingElements,
animateFlippedElements
}) => {
hideEnteringElements();
await animateExitingElements();
await animateFlippedElements();
animateEnteringElements();
}}
>
{items.map(({id}) => (
<Flipped
key={`item:${id}`}
flipId={`item:${id}`}
onAppear={onAppear}
onExit={onExit}
>
<button
style={{
width: 50,
height: 50,
display: vertical ? "block" : "inline-block"
}}
onClick={() => setItems(items.filter(({id: itemId}) => itemId !== id))}
>{id}</button>
</Flipped>
))}
</Flipper>
</div>
);
}
export default AddRemoveTest;
I don't know if it's the smae problem. I wrote this
<Flipped
key={file}
flipId={file}
onExit={onExit}
And onExit wasn't called.
I was using an object as a key and as flipId (but flipId has to be a string). Maybe a check could be added to throw an error if flipId is not a string (or I should be more carefull when reading prop documentation) ?
Does the flip toolkit support animating new items entering (and exiting)?
If I have an array that goes from 0 elements to 10 elements they simply "appear" without any animation. However, if I "shuffle" the array to reorder the existing items it animates very nicely.
I'd really like to get a simple "stacked" animation for new items, perhaps with a direction of appearance (from bottom) or "grow in place" (scale) or even just opacity (or some combination).