I have some problems with my code atm..
as the lightbox function gets called the opacity goes from 1 to 0, and then to 1 / where as i would like it to go only from 0 to 1. This problem also happens when i set the Opacity to 0 directly in the main div's class.
on the websites first load, the first time i trigger the lightbox it goes only from 1 - 0 opacity / and i then have to click (making it render an empty div class), and then "reactivate" the lightbox, where it then works as stated above.
I don't know how to make it go smoothly back to 0, as doing the following doesn't work.
else {
setOpacity(0);
setTimeout(function () {
return(
<div></div>
)
}, 1000);
}
This is how the code looks now:
import React, { useState } from 'react'
function Lightbox(props){
const [opacity, setOpacity] = useState(0)
const handleClick = () => {
setOpacity(0);
props.click()
setTimeout(function () {
setOpacity(1);
}, 1000);
}
if(props.lightbox){
return(
<div style={{opacity}} className={"lightbox-container"} id="lightbox" onClick={handleClick}>
<img src={props.pitem.src} alt={props.pitem.title}></img>
<div className="lightbox-text">
<div className="lightbox-h1">
<h1>{props.pitem.title}</h1>
<h2>{'(' + props.pitem.type + ')'}</h2>
</div>
<h2>{props.pitem.director ? "Director: " + props.pitem.director : null || props.pitem.production ? "Production: " + props.pitem.production : null}</h2>
<h2>{"role: " + props.pitem.role}</h2>
</div>
</div>
)
} else {
return(
<div></div>
)
}
}
export default Lightbox\
.lightbox-container{
z-index: 999;
position: fixed;
display: flex;
width: 100%;
height: 100%;
transition: opacity 0.2s ease;
backdrop-filter: blur(4px);
background:linear-gradient(0deg, rgb(0, 0, 0), rgba(30, 47, 92, 0.9));
justify-content: center;
align-items: center;
flex-direction: row;
}
Related
I'm currently using Slick in order to make a carousel.
I'm having two issues right now, let's start with the first one.
1)
I'm currently using a slider in which i want to show 3 slides: the current image (Spyro), the previous one (Crash) and the next one (Tekken).
As you see, while the current slide correctly overlaps the previous one (Spyro > Crash), the next one overlaps the current slide (Tekken > Spyro).
Of course i want the current slide to be on top of both of them... How can i fix this?
I'm attacching the code below.
App.js
import "./App.css";
import { useEffect, useState } from "react";
import Slider from "react-slick";
import SliderData from "./SliderData";
import { AiOutlineArrowLeft, AiOutlineArrowRight } from "react-icons/ai";
function useWindowSize() {
const [size, setSize] = useState([window.innerHeight, window.innerWidth]);
useEffect(() => {
const handleResize = () => setSize([window.innerHeight, window.innerWidth]);
window.addEventListener("resize", handleResize);
}, [])
return size;
}
const array = SliderData.map((x) => {
return x.image;
})
console.log(array);
function App() {
const NextArrow = ({ onClick }) => {
return (
<div className="arrow next" onClick={onClick}>
<AiOutlineArrowRight />
</div>
);
};
const PrevArrow = ({ onClick }) => {
return (
<div className="arrow prev" onClick={onClick}>
<AiOutlineArrowLeft />
</div>
);
};
const [imageIndex, setImageIndex] = useState(0);
const [height, width] = useWindowSize();
const settings = {
className: "center",
infinite: true,
lazyLoad: true,
speed: 300,
slidesToShow: width > 1000 ? 3: 1,
centerMode: true,
centerPadding: "60px",
nextArrow: <NextArrow />,
prevArrow: <PrevArrow />,
beforeChange: (current, next) => {
console.log(current);
setImageIndex(next);
}
};
return (
<div className="App">
<Slider {...settings}>
{array.map((img, idx) => (
<div className={idx === imageIndex ? "slide activeSlide" : "slide"}>
<img src={img} alt={img} />
</div>
))}
</Slider>
</div>
);
}
export default App;
App.css
#import "~slick-carousel/slick/slick.css";
#import "~slick-carousel/slick/slick-theme.css";
.App {
width: 100%;
margin: 10rem auto;
height: 570px;
}
.slide img {
width: 35rem;
align-items: center;
margin: 0 auto;
z-index: 1;
}
.slide {
transform: scale(0.8);
transition: transform 300ms;
opacity: 0.5;
z-index: -1;
}
.activeSlide {
transform: scale(1.1);
align-items: center;
opacity: 1;
}
.arrow {
background-color: #fff;
position: absolute;
cursor: pointer;
z-index: 10;
}
.arrow svg {
transition: color 300ms;
}
.arrow svg:hover {
color: #68edff;
}
.next {
right: 3%;
top: 50%;
}
.prev {
left: 3%;
top: 50%;
}
SliderData.js
const SliderData = [
{
image:
"https://www.spaziogames.it/wp-content/uploads/2020/06/Crash-4-Pirate_06-29-20.jpg"
},
{
image:
"https://d2skuhm0vrry40.cloudfront.net/2018/articles/2018-07-18-14-24/news-videogiochi-spyro-reignited-trilogy-video-di-gameplay-livello-colossus-1531920251281.jpg/EG11/thumbnail/750x422/format/jpg/quality/60"
},
{
image: "https://i.ytimg.com/vi/OUh82pOFGDU/maxresdefault.jpg"
},
{
image: "https://www.psu.com/wp/wp-content/uploads/2020/07/MetalGearSolidRemake-1024x576.jpg"
}
];
export default SliderData;
2)
As you see, the active slide is not perfectly centered. Since i suck in CSS i did not use the display: flex; command.
What do you suggest? how can i fix this?
Thank you all.
You need to apply a position element to .slide for the z-index to work properly.
Note: z-index only works on positioned elements (position: absolute, position: relative, position: fixed, or position: sticky) and flex items (elements that are direct children of display:flex elements).
You can read more on z-index here
This is my answer for this issue. Basically you should set position and z-index for every item and set higher z-index for current active item
.App .slick-slide {
position: relative;
z-index: 1;
/* your choice, but make sure z-index of active slide is higher than this value */
}
.App .slick-slide.slick-current {
z-index: 10;
}
I have a straight forward react-comp. which I want to test the styling depending on the react state. The comp looks like the following:
React-comp.
const Backdrop = ({ showBackdrop }) => {
const backdropRef = useRef();
function getBackdropHeight() {
if (typeof window !== 'undefined') {
return `calc(${document.body.clientHeight}px -
${backdropRef.current?.offsetTop || 0}px)`;
}
return 0;
}
return (
<div
data-testid="backdrop"
className={classNames(styles.backdrop, showBackdrop ? styles.show : styles.hide)}
ref={backdropRef}
style={{ height: getBackdropHeight() }}
/>
);
};
Styling
.backdrop {
width: 100%;
position: absolute;
left: 0;
right: 0;
top: 156px;
background-color: rgba(0, 0, 0, 0.7);
z-index: 3;
...
}
.show {
opacity: 0;
visibility: hidden;
transition: visibility 0.25s, opacity 0.25s ease-out;
}
.hide {
opacity: 1;
visibility: hidden;
transition: opacity 0.25s ease-in;
}
And the error that I always get from the test is, that the element is visible:
Received element is visible:
<div class="backdrop hide" data-testid="backdrop" style="height: calc(0px -
0px);" />
21 | const { getByTestId } = renderWithIntl(<Backdrop showBackdrop={false} />);
22 |
> 23 | expect(getByTestId('backdrop')).not.toBeVisible();
| ^
24 | });
25 | });
26 |
Test
it("should not render visible backdrop on falsy state", () => {
const { getByTestId } = render(<Backdrop showBackdrop={false} />);
expect(getByTestId('backdrop')).not.toBeVisible();
});
Any way on how to get the element as not visible without using react inline styling!?
You can use toBeVisible() function from RTL.
Here you have docs:
https://github.com/testing-library/jest-dom#tobevisible
Example:
// element should not be visible on screen
expect(screen.queryByText('1')).not.toBeVisible();
I'm trying to add and remove active class when I click on different panels that triggers a transition, so if I click on different panels it works, as in it triggers the transition and then it ends it when other panel gets clicked, but if I want to click on a panel that was already opened and closed it won't trigger it again on the first click adn that's not good UX.
I'm writing it in React and I am a beginner so maybe I'm not doing something right.
You can see the code below, I hope I gave all the right information.
componentDidMount() {
ReactDom.findDOMNode(this).addEventListener("transitionend", (e) => {
if (
e.propertyName.includes("flex") &&
e.target.classList.contains("open")
) {
e.target.classList.add("open-active");
}
});
ReactDom.findDOMNode(this).addEventListener("click", (e) => {
const elems = document.querySelector(".open-active");
if (elems !== null) {
elems.classList.remove("open-active", "open", "opac");
}
e.target.className = "open-active";
console.log(e);
});
}
render() {
const { index, top, bottom, image, open, onClick } = this.props;
const style = {
backgroundImage: `url(${image})`,
};
const openValue = open ? "open opac" : "";
return (
<div
className={`panel ${openValue}`}
style={style}
onClick={() => {
onClick(index);
}}
>
</div>
And the CSS
.panel > * {
margin: 0;
width: 100%;
transition: transform 0.5s;
flex: 1 0 auto;
display: flex;
justify-content: center;
align-items: center;
}
.panel > *:first-child {
transform: translateY(-100%);
}
.panel.open-active > *:first-child {
transform: translateY(0);
}
.panel > *:last-child {
transform: translateY(100%);
}
.panel.open-active > *:last-child {
transform: translateY(0);
}
.panel p:nth-child(2) {
font-size: 4em;
}
.panel.open {
font-size: 16px;
flex: 5;
}
Hi you can follow this example:
import React, {useState} from "react";
import './styles/style.css'
export default function ShowHideExample() {
const [cssClass, setCssClass] = useState('hide');
return (
<div className="App">
<h2>Show or Hide div</h2>
<button onClick={() => {
(cssClass === 'hide')? setCssClass('show') : setCssClass('hide');
}}>Click me to show or hide the div
</button>
<div className={cssClass}>
<h1>This is dynamically shown</h1>
</div>
</div>
);
}
Here is the style.css file
.show{
display: block;
background: dodgerblue;
padding:20px;
}
.hide{
display: none;
}
I am building a carousel, very minimalist, using CSS snap points. It is important for me to have CSS only options, but I'm fine with enhancing a bit with javascript (no framework).
I am trying to add previous and next buttons to scroll programmatically to the next or previous element. If javascript is disabled, buttons will be hidden and carousel still functionnal.
My issue is about how to trigger the scroll to the next snap point ?
All items have different size, and most solution I found require pixel value (like scrollBy used in the exemple). A scrollBy 40px works for page 2, but not for others since they are too big (size based on viewport).
function goPrecious() {
document.getElementById('container').scrollBy({
top: -40,
behavior: 'smooth'
});
}
function goNext() {
document.getElementById('container').scrollBy({
top: 40,
behavior: 'smooth'
});
}
#container {
scroll-snap-type: y mandatory;
overflow-y: scroll;
border: 2px solid var(--gs0);
border-radius: 8px;
height: 60vh;
}
#container div {
scroll-snap-align: start;
display: flex;
justify-content: center;
align-items: center;
font-size: 4rem;
}
#container div:nth-child(1) {
background: hotpink;
color: white;
height: 50vh;
}
#container div:nth-child(2) {
background: azure;
height: 40vh;
}
#container div:nth-child(3) {
background: blanchedalmond;
height: 60vh;
}
#container div:nth-child(4) {
background: lightcoral;
color: white;
height: 40vh;
}
<div id="container">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
</div>
<button onClick="goPrecious()">previous</button>
<button onClick="goNext()">next</button>
Nice question! I took this as a challenge.
So, I increased JavaScript for it to work dynamically. Follow my detailed solution (in the end the complete code):
First, add position: relative to the .container, because it need to be reference for scroll and height checkings inside .container.
Then, let's create 3 global auxiliary variables:
1) One to get items scroll positions (top and bottom) as arrays into an array. Example: [[0, 125], [125, 280], [280, 360]] (3 items in this case).
3) One that stores half of .container height (it will be useful later).
2) Another one to store the item index for scroll position
var carouselPositions;
var halfContainer;
var currentItem;
Now, a function called getCarouselPositions that creates the array with items positions (stored in carouselPositions) and calculates the half of .container (stored in halfContainer):
function getCarouselPositions() {
carouselPositions = [];
document.querySelectorAll('#container div').forEach(function(div) {
carouselPositions.push([div.offsetTop, div.offsetTop + div.offsetHeight]); // add to array the positions information
})
halfContainer = document.querySelector('#container').offsetHeight/2;
}
getCarouselPositions(); // call it once
Let's replace the functions on buttons. Now, when you click on them, the same function will be called, but with "next" or "previous" argument:
<button onClick="goCarousel('previous')">previous</button>
<button onClick="goCarousel('next')">next</button>
Here is about the goCarousel function itself:
First, it creates 2 variables that store top scroll position and bottom scroll position of carousel.
Then, there are 2 conditionals to see if the current carousel position is on most top or most bottom.
If it's on top and clicked "next" button, it will go to the second item position. If it's on bottom and clicked "previous" button, it will go the previous one before the last item.
If both conditionals failed, it means the current item is not the first or the last one. So, it checks to see what is the current position, calculating using the half of the container in a loop with the array of positions to see what item is showing. Then, it combines with "previous" or "next" checking to set the correct next position for currentItem variable.
Finally, it goes to the correct position through scrollTo using currentItem new value.
Below, the complete code:
var carouselPositions;
var halfContainer;
var currentItem;
function getCarouselPositions() {
carouselPositions = [];
document.querySelectorAll('#container div').forEach(function(div) {
carouselPositions.push([div.offsetTop, div.offsetTop + div.offsetHeight]); // add to array the positions information
})
halfContainer = document.querySelector('#container').offsetHeight/2;
}
getCarouselPositions(); // call it once
function goCarousel(direction) {
var currentScrollTop = document.querySelector('#container').scrollTop;
var currentScrollBottom = currentScrollTop + document.querySelector('#container').offsetHeight;
if (currentScrollTop === 0 && direction === 'next') {
currentItem = 1;
} else if (currentScrollBottom === document.querySelector('#container').scrollHeight && direction === 'previous') {
console.log('here')
currentItem = carouselPositions.length - 2;
} else {
var currentMiddlePosition = currentScrollTop + halfContainer;
for (var i = 0; i < carouselPositions.length; i++) {
if (currentMiddlePosition > carouselPositions[i][0] && currentMiddlePosition < carouselPositions[i][1]) {
currentItem = i;
if (direction === 'next') {
currentItem++;
} else if (direction === 'previous') {
currentItem--
}
}
}
}
document.getElementById('container').scrollTo({
top: carouselPositions[currentItem][0],
behavior: 'smooth'
});
}
window.addEventListener('resize', getCarouselPositions);
#container {
scroll-snap-type: y mandatory;
overflow-y: scroll;
border: 2px solid var(--gs0);
border-radius: 8px;
height: 60vh;
position: relative;
}
#container div {
scroll-snap-align: start;
display: flex;
justify-content: center;
align-items: center;
font-size: 4rem;
}
#container div:nth-child(1) {
background: hotpink;
color: white;
height: 50vh;
}
#container div:nth-child(2) {
background: azure;
height: 40vh;
}
#container div:nth-child(3) {
background: blanchedalmond;
height: 60vh;
}
#container div:nth-child(4) {
background: lightcoral;
color: white;
height: 40vh;
}
<div id="container">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
</div>
<button onClick="goCarousel('previous')">previous</button>
<button onClick="goCarousel('next')">next</button>
Another good detail to add is to call getCarouselPositions function again if the window resizes:
window.addEventListener('resize', getCarouselPositions);
That's it.
That was cool to do. I hope it can help somehow.
I've just done something similar recently. The idea is to use IntersectionObserver to keep track of which item is in view currently and then hook up the previous/next buttons to event handler calling Element.scrollIntoView().
Anyway, Safari does not currently support scroll behavior options. So you might want to polyfill it on demand with polyfill.app service.
let activeIndex = 0;
const container = document.querySelector("#container");
const elements = [...document.querySelectorAll("#container div")];
function handleIntersect(entries){
const entry = entries.find(e => e.isIntersecting);
if (entry) {
const index = elements.findIndex(
e => e === entry.target
);
activeIndex = index;
}
}
const observer = new IntersectionObserver(handleIntersect, {
root: container,
rootMargin: "0px",
threshold: 0.75
});
elements.forEach(el => {
observer.observe(el);
});
function goPrevious() {
if(activeIndex > 0) {
elements[activeIndex - 1].scrollIntoView({
behavior: 'smooth'
})
}
}
function goNext() {
if(activeIndex < elements.length - 1) {
elements[activeIndex + 1].scrollIntoView({
behavior: 'smooth'
})
}
}
#container {
scroll-snap-type: y mandatory;
overflow-y: scroll;
border: 2px solid var(--gs0);
border-radius: 8px;
height: 60vh;
}
#container div {
scroll-snap-align: start;
display: flex;
justify-content: center;
align-items: center;
font-size: 4rem;
}
#container div:nth-child(1) {
background: hotpink;
color: white;
height: 50vh;
}
#container div:nth-child(2) {
background: azure;
height: 40vh;
}
#container div:nth-child(3) {
background: blanchedalmond;
height: 60vh;
}
#container div:nth-child(4) {
background: lightcoral;
color: white;
height: 40vh;
}
<div id="container">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
</div>
<button onClick="goPrevious()">previous</button>
<button onClick="goNext()">next</button>
An easier approach done with react.
export const AppCarousel = props => {
const containerRef = useRef(null);
const carouselRef = useRef(null);
const [state, setState] = useState({
scroller: null,
itemWidth: 0,
isPrevHidden: true,
isNextHidden: false
})
const next = () => {
state.scroller.scrollBy({left: state.itemWidth * 3, top: 0, behavior: 'smooth'});
// Hide if is the last item
setState({...state, isNextHidden: true, isPrevHidden: false});
}
const prev = () => {
state.scroller.scrollBy({left: -state.itemWidth * 3, top: 0, behavior: 'smooth'});
setState({...state, isNextHidden: false, isPrevHidden: true});
// Hide if is the last item
// Show remaining
}
useEffect(() => {
const items = containerRef.current.childNodes;
const scroller = containerRef.current;
const itemWidth = containerRef.current.firstElementChild?.clientWidth;
setState({...state, scroller, itemWidth});
return () => {
}
},[props.items])
return (<div className="app-carousel" ref={carouselRef}>
<div className="carousel-items shop-products products-swiper" ref={containerRef}>
{props.children}
</div>
<div className="app-carousel--navigation">
<button className="btn prev" onClick={e => prev()} hidden={state.isPrevHidden}><</button>
<button className="btn next" onClick={e => next()} hidden={state.isNextHidden}>></button>
</div>
</div>)
}
I was struggling with the too while working with a react project and came up with this solution. Here's a super basic example of the code using react and styled-components.
import React, { useState, useRef } from 'react';
import styled from 'styled-components';
const App = () => {
const ref = useRef();
const [scrollX, setScrollX] = useState(0);
const scrollSideways = (px) => {
ref.current.scrollTo({
top: 0,
left: scrollX + px,
behavior: 'smooth'
});
setScrollX(scrollX + px);
};
return (
<div>
<List ref={ref}>
<ListItem color="red">Card 1</ListItem>
<ListItem color="blue">Card 2</ListItem>
<ListItem color="green">Card 3</ListItem>
<ListItem color="yellow">Card 4</ListItem>
</List>
<button onClick={() => scrollSideways(-600)}> Left </button>
<button onClick={() => scrollSideways(600)}> Right </button>
</div>
);
};
const List = styled.ul`
display: flex;
overflow-x: auto;
padding-inline-start: 40px;
scroll-snap-type: x mandatory;
list-style: none;
padding: 40px;
width: 700px;
`;
const ListItem = styled.li`
display: flex;
flex-shrink: 0;
scroll-snap-align: start;
background: ${(p) => p.color};
width: 600px;
margin-left: 15px;
height: 200px;
`;
I have an image on a React page. When the state is updated to a new image I want to perform the following transition effect:
The original image should zoom in and fade out
The new image should also zoom in and fade in
The effect should look similar to passing through a wall to a new scene.
How am I able to do this in React?
As #pgsandstrom mentioned, React Transition Group is the way to go. Unfortunately, it's not very developer friendly (pretty steep learning curve).
Here's a working example: https://codesandbox.io/s/6lmv669kz
✔ Original image zooms in while fading out
✔ New image zooms in while fading in
TransitionExample.js
import random from "lodash/random";
import React, { Component } from "react";
import { CSSTransition, TransitionGroup } from "react-transition-group";
import uuid from "uuid/v1";
const arr = [
{
id: uuid(),
url: `https://loremflickr.com/600/100?lock=${random(0, 999)}`
},
{
id: uuid(),
url: `https://loremflickr.com/600/100?lock=${random(0, 999)}`
},
{
id: uuid(),
url: `https://loremflickr.com/600/100?lock=${random(0, 999)}`
}
];
export default class TransitionExample extends Component {
state = {
index: 0,
selected: arr[0]
};
nextImage = () =>
this.setState(prevState => {
const newIndex = prevState.index < arr.length - 1 ? prevState.index + 1 : 0;
return {
index: newIndex,
selected: arr[newIndex]
};
});
render = () => (
<div className="app">
<div style={{ marginBottom: 30, height: 100 }}>
<TransitionGroup>
<CSSTransition
key={this.state.selected.id}
timeout={1000}
classNames="messageout"
>
<div style={{ marginTop: 20 }}>
<img className="centered-image" src={this.state.selected.url} />
</div>
</CSSTransition>
</TransitionGroup>
</div>
<div style={{ textAlign: "center" }}>
<button
className="uk-button uk-button-primary"
onClick={this.nextImage}
>
Next Image
</button>
</div>
</div>
);
}
styles.css
.app {
margin: 0 auto;
overflow: hidden;
width: 700px;
height: 800px;
}
.centered-image {
display: block;
margin: 0 auto;
}
/* starting ENTER animation */
.messageout-enter {
position: absolute;
top: 0;
left: calc(13% + 5px);
right: calc(13% + 5px);
opacity: 0.01;
transform: translateY(0%) scale(0.01);
}
/* ending ENTER animation */
.messageout-enter-active {
opacity: 1;
transform: translateY(0%) scale(1);
transition: all 1000ms ease-in-out;
}
/* starting EXIT animation */
.messageout-exit {
opacity: 1;
transform: scale(1.01);
}
/* ending EXIT animation */
.messageout-exit-active {
opacity: 0;
transform: scale(4);
transition: all 1000ms ease-in-out;
}
It sounds like you are looking for React Transition Group. It is the "official" way of solving these issues. Specifically I think this is what you should use. It can be a bit tricky to get a hang of, but it is really nice and powerful once you understand it.
This worked for me (link):
index.js:
import React from "react";
import { render } from "react-dom";
import "./styles.scss";
const src1 =
"https://www.nba.com/dam/assets/121028030322-james-harden-traded-102712-home-t1.jpg";
const src2 = "https://www.nba.com/rockets/sites/rockets/files/wcwebsite.jpg";
var state = {
toggle: true
};
class App extends React.Component {
render() {
const cn1 = "imgFrame " + (state.toggle ? "toggleOut" : "toggleIn");
const cn2 = "imgFrame " + (state.toggle ? "toggleIn" : "toggleOut");
return (
<div>
<img className={cn1} src={src1} alt={"img1"} />
<img className={cn2} src={src2} alt={"img2"} />
<button
onClick={() => {
state.toggle = !state.toggle;
this.forceUpdate();
}}
>
click me to toggle
</button>
<h1>Hello</h1>
</div>
);
}
}
render(<App />, document.getElementById("app"));
style.scss:
html,
body {
background-color: papayawhip;
font-family: sans-serif;
h1 {
color: tomato;
}
}
#keyframes fadeout {
0% {
opacity: 1;
transform: scale(1);
}
100% {
opacity: 0;
transform: scale(0.9);
}
}
#keyframes fadein {
0% {
opacity: 0;
transform: scale(1.1);
}
100% {
opacity: 1;
transform: scale(1);
}
}
.toggleOut {
animation: fadeout 500ms;
opacity: 0;
}
.toggleIn {
animation: fadein 500ms;
opacity: 1;
}
.imgFrame {
position: absolute;
top: 10px;
left: 10px;
width: 200px;
height: 200px;
}
button {
position: absolute;
top: 220px;
}
Wrap with a simple <Animate on={value} /> component that triggers an animation when value changes and is not undefined.
function Animate({ children, on }) {
return (on === undefined)
? <div>{children}</div>
: <div className="fade-in" key={on}>{children}</div>
}
import { useEffect, useState } from 'react'
function TestAnimate() {
const [value, setValue] = useState() // undefined
// update value every second
useEffect(() => {
setInterval(() => setValue(new Date().toLocaleString()), 1_000)
}, [])
return (
<Animate on={value}>
Value: {value}
</Animate>
)
}
#keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.fade-in {
animation: fadeIn 500ms ease-in-out;
}