I am working on a project and I am new with animation and my objective is from a group of buttons when the user click on the button become active and a line will move from button to button.
I managed to make the button active and change color and etc, the only thing i still can`t make is that line to move from button to button.
This is my Reactjs code
class AnimateButtonArea extends Component {
constructor(props){
super(props)
this.state = { active: 0 };
}
setActive = (key) => {
this.setState({ active: key });
}
render() {
return (
<div className = "AnimateButtonArea">
{data.AnimateButton.map((animateButton, key) => {
return(
<div key = {key} className = { this.state.active === key ? "AnimateButton active" : "AnimateButton"} >
<Button type = {this.state.active === key ? "SofiaProBlackSmallActive" : "SofiaProBlackSmall"} onClick = {() => { this.setActive(key) }} text = {animateButton.button} />
<div className = "animatedLine" />
</div>
)
})}
</div>
)
}
}
export default AnimateButtonArea;
And this is my Sass code
.AnimateButtonArea
display: inline-block
.AnimateButton
display: inline-block
margin-right: 147px
.AnimateButton.active .animatedLine
position: relative
height: 8px
left: 24px
background: var(--yellow)
border-radius: 40px
text-align: center
animation: grow 0.4s ease-out
#keyframes grow
0%
width: 0%
100%
width: 100%
UPDATE
Now I can move the line but now i want to increase the line and then decrease and move it
Here's the updated Reactjs part
setActive = (key) => {
this.setState({ active: key })
var difference = key - this.state.active
leftActive += 300 * difference
style = { width: `calc(${leftActive}px + 120px)`}
setTimeout(()=> this.beActive(leftActive), 1000)
}
beActive = (leftActive) => {
style = { marginLeft: `calc(${leftActive}px)`, with: `120px`}
console.log(style);
}
To move between positions, the line should be an unique object outside of the mapped array. Then you can manipulate the positioning (with margin, transform or left) based on the key/(array.length-1) with inline styles.
Set css transition: all 1s ease; to animate.
I would pass the width to state (this.state.activeWidth) and include it in the line style object. {width:this.state.activeWidth}
Related
I am using the React Beautiful DND library to drag items(square divs) between columns or reordered in the same column. I followed their Egghead video tutorial to change the background color of the div as it's being dragged. When it gets dropped, it switches back to the default color of all other items. I want it to slowly fade(like 1 second maybe) to the default color after it is dropped.
Here is my current code styling for the div as it's being dragged and dropped. I added the transition line, that but is not doing anything.
const MyOrder = styled.div`
background-color: ${(props) =>
props.isDragging ? '#4FB740' : '#193DF4'};
transition: background-color 1s ease;
`;
I have tried adding this code to the onDragEnd event:
setDroppedOrderID(theOrder.orderNumber);
setTimeout(() => {
setDroppedOrderID('');
}, 2000);
And I made the order div that gets dragged look like this:
<MyOrder
id={orderNumber}
className={`order size-${size} ${
droppedOrderID === orderNumber ? ' dropped' : ''
} ${palletLoc === 'OUTSIDE' ? 'outside' : ''}`}
But it is buggy if someone tries to drag the same item in less than the 2 second time interval.
You can actually style the drop and do animation
See working demo & full code here in the codesandbox
You need to use isDropAnimating property from the snapshot to check if animation is being done so that you can conditionally return the original style.
code snippet
const OpportunityContainer = styled.div`
border: 1px solid #ddd;
border-radius: 0.3rem;
background: #fff;
padding: 1rem;
margin-bottom: 0.8rem;
transition: background-color 5s ease;
background-color: ${props => (props.isDragging ? "#4FB740" : "#193DF4")};
`;
function getStyle(style, snapshot) {
if (!snapshot.isDropAnimating) {
return style;
}
// patching the existing style
return {
...style,
transition: `all 3s ease`,
backgroundColor: "blue"
};
}
const Opportunity = React.memo(({ index, id, title }) => {
return (
<Draggable draggableId={id} index={index}>
{(provided, snapshot) => (
<OpportunityContainer
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
isDragging={snapshot.isDragging && !snapshot.isDropAnimating}
style={getStyle(provided.draggableProps.style, snapshot)}
>
{title}
</OpportunityContainer>
)}
</Draggable>
);
});
export default Opportunity;
Note - Make sure to read this note in the library documentation. isDragging will be true until animation/fade-out is completed. Therefore try to provide less duration for your animation (eg: 1 second or less than 1 second)
Example is a functional component in which I am rendering a div conditionally. I want this div to fade-in when rendered conditionally and fade-out vice versa.
For that, I have maintained two local state variables: render and fadeIn which are computed based on show prop passed down to the Example component.
What I've done is:
When show prop it true, I set render as true, so the div renders conditionally and after a timeout of 10ms I set fadeIn as true which will set CSS classname for my div as show.
When show prop it false, I set fadeIn as false, which will set CSS classname for my div as hide and after a timeout of 200ms (transition time in CSS) I set render as false so the div is hidden conditionally.
Code:
interface Props {
show: boolean;
}
const Example: React.FC<Props> = ({ show, }) => {
const [render, setRender] = useState(false);
const [fadeIn, setFadeIn] = useState(false);
useEffect(() => {
if (show) {
// render component conditionally
setRender(show);
// change state to for conditional CSS classname which will
// animate opacity, I had to give a timeout of 10ms else the
// component shows up abruptly
setTimeout(() => {
setFadeIn(show);
}, 10);
} else {
// change state to change component classname for opacity animation
setFadeIn(false);
// hide component conditionally after 200 ms
// because that's the transition time in CSS
setTimeout(() => {
setRender(false);
}, 200);
}
}, [
show,
]);
return (
<div>
{render && (
<div className={`container ${fadeIn ? 'show' : 'hide'}`} />
)}
</div>
);
};
Stylesheet:
.container {
width: 100px;
height: 100px;
background-color: black;
transition: opacity 0.2s ease;
}
.show {
opacity: 1;
}
.hide {
opacity: 0;
}
I believe this is not a good coding practice to achieve the functionality and should maintain only one local state in my component. I need your suggestions on how I can solve this in a better way without using any 3rd Party Library.
Thanks :)
const [render, setRender] = useState(false);
useEffect(() => {
if(show) {
setTimeout(() => {
setRender(true);
}, 2000);
} else {
setRender(false);
}
}, [show]);
<div className={cs(s.render, render ? 'show' : undefined)}>
<p>{content}</p>
</div>
Css:
.render {
...,
visibility: hidden;
opacity: 0;
transition: all 0.6s ease;
}
.show {
visibility: visible;
opacity: 1;
}
Hope be helpful.
Thanks for reading. I am trying to check a function whether true of false. If false, I would like to change the border color to red, appear and disappear and appear and disappear in 2 seconds. I just tried the css animation to achieve it, but it only appear one time.
https://codesandbox.io/s/38qvr0j3lp
I wonder if there is a way using CSS to achieve it. Any help would be appreciated.
Here's a little demo - on click I'm adding an animation (via keyframes instead of transition) to the button element.
The keyframe animation begins with a red border, and has a transparent border in the middle. By using this in conjunction with steps(1), the animation is treated like it consists of two frames (at 0% and 50%), alternating transparent and red. I run this animation twice (that's the 2) over 1 second each time (that's the 1s).
In the JS, note that I'm removing the blink class and readding it 10ms later in case it's already there. You can't retrigger a CSS keyframe animation without removing and readding the property.
function blink(el) {
el.classList.remove("blink")
setTimeout(function() {
el.classList.add("blink")
}, 10);
}
button {
border: 1px solid transparent;
outline: none;
}
.blink {
animation: border-blink 1s steps(1) 2;
}
#keyframes border-blink {
0% {
border-color: red;
}
50% {
border-color: transparent;
}
}
<button onclick="blink(this)">Click Me</button>
Fixed the code in your code sandbox with a totally React approach.
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
error: false
};
}
showErrorSignal() {
this.setState({ error: true });
setTimeout(() => this.setState({ error: false }), 500);
setTimeout(() => this.setState({ error: true }), 1000);
setTimeout(() => this.setState({ error: false }), 1500);
}
render() {
const styles = {
error: {
borderWidth: 5,
borderColor: "red"
}
};
return (
<div className="App" style={this.state.error ? styles.error : undefined}>
<h1>Hello CodeSandbox</h1>
<button onClick={() => this.showErrorSignal()}>
show error signal
</button>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
.App {
font-family: sans-serif;
text-align: center;
border: 3px solid #d5edeb;
transition-property: border-color, border-width;
transition-duration: 500ms;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root" />
I am writing a ReactJS component for the first time. I have a tooltip which needs to have a dynamic delay value on mouseenter and mouseleave events. I am currently using a hover approach in CSS with transition-delay. This solution is working for me however, I need to be able to setState and update each of the transition-delay (see below) through my component. I need to be able to accomplish this with pure ReactJS/Javascript (no JQuery etc).
Here is a sample of my code:
.tooltip .tooltiptext {
visibility: hidden;
width: 120px;
background-color: #555;
color: #fff;
text-align: center;
border-radius: 6px;
padding: 5px 0;
position: absolute;
z-index: 1;
bottom: 125%;
left: 50%;
margin-left: -60px;
opacity: 0;
transition-delay: 2s;
}
.tooltip:hover .tooltiptext {
visibility: visible;
opacity: 1;
transition-delay: 1s;
}
How can I access each of these transition-delay properties from the component and change the value with setState?
Thanks for your help
Update: I have figured out how to update the CSS property through JS. I now need to be able to reset the state. Please see my comment from below.
Here is some additional code:
constructor(props) {
super(props);
this.state = {
userInput: '',
transitionDelay: '0s'
}
handleMouseEnterDelay() {
var mouseIn = document.getElementById('tooltip');
var delayIn = mouseIn.style.transitionDelay = '0s';
this.setState({
transitionDelay: {delayIn}
})
}
handleMouseLeaveDelay() {
var mouseLeave = document.getElementById('tooltiptext');
var delayLeave = mouseLeave.style.transitionDelay = '4s';
this.setState({
transitionDelay: {delayLeave}
})
So what I need is that after each hover event i need transitionDelay to take the values defined in the function. I.e. after first mouseenter/leave event it stays to 4s, so the second time I go to hover(enter) then it is a 4s delay for both enter and leave. I need the enter delay to go back to 0s as defined in the handleMouseEnterDelay function.
Is there a way which I can have two 'transitionDelay' values in setState? I tried a nested object i.e. in:{transitionDelay}, out:{transitionDelay} but i couldn't access it while setting state.
Maybe something like...
constructor() {
this.state = {
style: {
transitionDelay: '1s'
}
};
this.toggleDelay = this.toggleDelay.bind(this);
}
toggleDelay(state) {
this.setState({ style: { transitionDelay: state ? '2s' : '1s' } });
}
...
render() {
return (
<div className="tooltip" style={this.state.style} onMouseEnter={() => this.toggleDelay(true)} onMouseLeave={() => this.toggleDelay(false)}>
.....
</div>
);
}
Can some one point me to a simple example using CSS transitions no other libraries in reactjs to animate image from negative to positive right/left positions on component load?
Here is what you are looking for
.example-enter {
opacity: 0.01;
position: relative;
left: -100px
}
.example-enter.example-enter-active {
opacity: 1;
position: relative;
left: 0;
transition: all 1s ease-in;
}
Component
class Container extends React.Component {
constructor(props) {
super(props);
this.state = {
items: [0],
counter: 0
};
this.handleAdd = this.handleAdd.bind(this);
}
handleAdd(){
const counter = this.state.counter + 1,
items = this.state.items.concat([counter]);
this.setState({
counter,items
})
}
render(){
const items = this.state.items.map(item => {
return <li className='example' key={item}>{item}</li>
})
return <ul className='container'>
<ReactCSSTransitionGroup
transitionName="example"
transitionEnterTimeout={500}
transitionLeaveTimeout={300}>
{items}
</ReactCSSTransitionGroup>
<hr/>
<button onClick={this.handleAdd}>New One</button>
</ul>
}
}
React.render(<Container />, document.getElementById('container'));
And also link to >> React Animation & worked fiddle
Thanks