I got a little tricky problem.
I am having a container with is being coloured on clicking it. Clicking it will result in sending data to array, but thats not the problem.
Clicking it will also animate the change of colour. Animation will be triggered forward on click, and backwards if container will be clicked again.
The issue is that animation is triggered conditionally with use of useState (boolean) and thus, the second animation will be running already when page is loaded, before even clicking the container. I was wondering about animation-play-state style, but it not seems to be sufficient.
Heres the editable demo https://qeevsk.csb.app/ Any ideas, maybe there is better aproach ?
The code itself:
const [activeDiv, setDivState] = useState(false);
const BigDiv = styled("div")(
({ theme, activeDiv }) => css`
min-width: 220px;
height: 100%;
position: relative;
padding: ${theme.spacing(2, 0)};
border-bottom: red 4px solid;
background-color: transparent;
cursor: pointer;
text-align: center;
transition-delay: 0.5s;
will-change: transform;
::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
background-color: ${activeDiv ? "red" : "transparent"};
animation: ${activeDiv ? setColor("red") : unsetColor("red")}
0.5s ease ;
transform-origin: bottom center};
}
`
);
const setColor = (colorTo) => keyframes`
0% {transform: scaleY(0); }
100% {transform: scaleY(1); background-color: ${colorTo}}
`;
const unsetColor = (colorFrom) => keyframes`
0% {transform: scaleY(1); background-color: ${colorFrom}}
100% {transform: scaleY(0); background-color: transparent;}
`;
const SecondDiv = styled("div")(
({ theme, activeDiv, color }) => css`
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
position: relative;
z-index: 1;
`
);
return (
<>
<BigDiv
activeDiv={activeDiv}
onClick={(e) => {
setDivState(!activeDiv);
}}
>
<SecondDiv>
<p>Click to animate</p>
</SecondDiv>
</BigDiv>
</>
);
}
CodePudding user response:
You can define a state variable something like startAnimation
and set to to false by default.
When user click on click it to continue
then set it to true and apply animation accordingly
Defined state
const [startAnimation, setStart] = useState(false);
Pass it in component
<BigDiv
activeDiv={activeDiv}
startAnimation={startAnimation}
onClick={(e) => {
setStart(true);
setDivState(!activeDiv);
}}
>
<SecondDiv>
<p>Click to animate</p>
</SecondDiv>
</BigDiv>
</>
Use it in component like this
const BigDiv = styled("div")(
({ theme, activeDiv, startAnimation }) => css`
min-width: 220px;
height: 100%;
position: relative;
padding: ${theme.spacing(2, 0)};
border-bottom: red 4px solid;
background-color: transparent;
cursor: pointer;
text-align: center;
transition-delay: 0.5s;
will-change: transform;
::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
background-color: ${activeDiv ? "red" : "transparent"};
animation: ${
startAnimation ? (activeDiv ? setColor("red") : unsetColor("red")) : ""
}
0.5s ease ;
transform-origin: bottom center};
}
`
);
CodePudding user response:
Easiest fix I could think of was to set the initial activeDiv state to null
and change the animation rule to:
animation: ${activeDiv ? setColor("red") : unsetColor("red")} ${activeDiv === null ? "0" : "0.5s ease"} ;
Now there won't be any animation at startup, but it will animated if activeDiv is anything but null.
Here is my fork: https://codesandbox.io/s/animate-divs-forked-gth814