How to show Vertical Progress Bar in react-transition-group with animation - reactjs

Here is a jQuery example for a progress bar animation. and I want this feature in Reactjs without jQuery. How to implement this feature.

I hope you are still interested in this question. I just tinker with react-spring and I really love it. The best animation library in React IMHO.
You can create a neat component with the Spring component. It will always animate to the to property of the Spring component. First time from the from value of the from property.
import React from "react";
import { Spring } from "react-spring";
const VerticalProgress = ({ progress }) => {
return (
<Spring from={{ percent: 0 }} to={{ percent: progress }}>
{({ percent }) => (
<div className="progress vertical">
<div style={{ height: `${percent}%` }} className="progress-bar">
<span className="sr-only">{`${progress}%`}</span>
</div>
</div>
)}
</Spring>
);
};
export default VerticalProgress;
Here is the complete code: https://codesandbox.io/s/mqo1r9wo4j

Horizontal Example
Here is how to do it.
make 2 divs(container, progressing one)
you can change the height of progressing div based on state change.
const styled = styled.default;
const Bar = styled.div`
position: relative;
height: 500px;
width: 100%;
border-radius: 3px;
border: 1px solid #ccc;
margin: 1rem auto;
`
const Fill = styled.div`
background: #0095da;
width: 100%;
border-radius: inherit;
transition: height 0.2s ease-in;
height: ${(props) => `${props.percentual}%`};
`
const ProgressBar = ({ percentage }) => {
return (
<div>
<Bar>
<Fill percentage={percentage} />
</Bar>
</div>
);
}
ReactDOM.render(<ProgressBar percentage={you state for progress percentage} />, document.getElementById('bar'));
you don't even need react for that tho.
https://www.w3schools.com/howto/tryit.asp?filename=tryhow_js_progressbar_label_js

Related

I want the arrow icon to flip up and down every time the state changes.and I want to animate it

I am using react, styled-components.
When state(visible) is set to true, DropMenu box1 and box2 will be displayed.
We want the ArrowDown icon to flip upward when state is true, and downward when false.
I also want to apply an animation when flipping it.
I want to add an animation like the Dropdown in the following site.  
Reference site
code
import "./styles.css";
import styled from "styled-components";
import React, { useState, useCallback } from "react";
import { ArrowDown } from "./ArrowDown";
const Item = styled.div<{ active?: boolean }>`
height: 40px;
width: 300px;
padding: 0px 30px;
&:hover {
background: #fafbfb;
}
`;
const DropMenu = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
color: #899098;
width: 100%;
height: 100%;
font-size: 14px;
font-weight: bold;
gap: 12px;
:hover {
color: gray;
}
div {
display: flex;
align-items: center;
gap: 12px;
}
`;
const DropText = styled.div`
padding-left: 32px;
`;
export const App = () => {
const [visible, setVisible] = useState(false);
const handleDropVisibleChange = useCallback(() => {
setVisible((prevVisible) => !prevVisible);
}, [visible]);
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<Item onClick={handleDropVisibleChange}>
<DropMenu>
<div>
<span>Menu</span>
</div>
<ArrowDown />
</DropMenu>
</Item>
{visible && (
<div style={{ transition: "all 0.5s ease" }}>
<Item>
<DropMenu>
<DropText>box1</DropText>
</DropMenu>
</Item>
<Item>
<DropMenu>
<DropText>box2</DropText>
</DropMenu>
</Item>
</div>
)}
</div>
);
};
export default App;
TLDR
Change your MenuItem component warpper to something like
const DropMenuWrapper = styled.div<{ visible: boolean }>`
transition: all 0.5s ease;
opacity: ${(props) => (props.visible ? 1 : 0)};
`;
replace the visibility switch mechanism with following
- {visible && (
- <div style={{ transition: "all 0.5s ease" }}>
+ <DropMenuWrapper visible={visible}>
similar action can be added to the arrow-down icon also with style
(The ArrowDown SVG icon must accept style if it is custom written component)
<ArrowDown
style={{
transition: "all 0.5s ease",
transform: `rotate(${visible ? 0 : "0.5turn"})`
}}
/>
Why this happened:
When a component (sub-component/element) is mounted in react, it starts a complete life cycle toward browser paint.
So it is must have the property which causes the element to animate, for example, I added the opacity transition to the example itself, forcing it to animate in the first look and in disappearing.
Although it comes with some performance cost of having unseen elements still in the dom (but not visible), making it bad for accessibility too, it is the simplest way to achieve this behavior.
Consider this example If you have an animated element, does it show the animation if you refresh the browser if the answer is yes, it will show animation in react too.
Another way of doing some animation in react.
Using third-party library react-transtion-group which is heavily used in lots of packages e.g. Material-UI.
In this case you can also trigger the end event and start to unmount the component as the animation disappears and end completely.
Using framer motion
If you want to take your understanding of what is needed for the transition when the component is unmounted and removed from aka dom, I highly encourage you to read the animation section of svelte docuementation
What I did, what might look stupid to more advanced developers was implement a simple check that would switch icons.
Note: This doesn't have an animation, though. It's just a simple switcharoo
define state in component
const [isOpen, setIsOpen] = useState(false);
Check whether icon is open or closed, if open, ExpandLessIcon, if closed ExpandMoreIcon.
<ExpandLessIcon
onClick={() => {
setIsOpen(!isOpen);
}}
/>
) : (
<ExpandMoreIcon
onClick={() => {
setIsOpen(!isOpen);
}}
/>
)}
The way it works is, once clicked, it'll just flip the true false state over and over, which in turn will change icons.

How to loop a Draggable slider in React

I have a draggable horizontal slider in my current project and I would like to setting up it also to loop continuously. By loop continuously I mean it should respond to the process of showing images one after another when dragging? Right now, I do have only 3 images in my slider and when I drag slider to the left, slider with its 3rd image and a blank white space starts showing just after. Here at this point I want images to get start again continuously from the very beginning i.e. from the 1st image with aim to cover the white blank space.
Apart, one error I'm getting with my existing code is that when I start to drag slider to right side, suddenly a scroll comes up on browser and keep going in never ending state. By never ending state, I mean it still remain on screen when I drag all my 3 images fully in right direction.
So these are the two things I want to apply and want to resolve in my current project. I'm sharing my code below.
src > Routes > Home > Components > Carousel > Components > SliderDataItems > index.js
import React, { useRef, useEffect } from "react";
import { gsap } from "gsap";
import { Draggable } from "gsap/Draggable";
import { ZoomInOutlined } from '#ant-design/icons'
import { Images } from '../../../../../../Shared/Assets';
import ImagesIcon from '../../../../../../Components/Cells/ImagesIcon'
gsap.registerPlugin(Draggable);
const pictures = [
{
img: Images.xgallery1,
icon: <ZoomInOutlined />
},
{
img: Images.xgallery2,
icon: <ZoomInOutlined />
},
{
img: Images.xgallery4,
icon: <ZoomInOutlined />
},
];
const Slide = ({ img, icon }) => {
return (
<div className="slide">
<div className="image">
<ImagesIcon src={img} />
<div className="icon">
{icon}
</div>
</div>
</div>
);
};
export const Slider = () => {
const sliderRef = useRef(null);
useEffect(() => {
Draggable.create(sliderRef.current, {
type: "x"
});
}, []);
return (
<div className="slider" ref={sliderRef}>
{pictures.map((item, index) => {
return (
<Slide key={index} img={item.img} icon={item.icon} />
);
})}
</div>
);
};
export default Slider;
src > Routes > Home > Components > Carousel > style.scss
.slider {
display: flex;
cursor: unset !important;
overflow: hidden !important;
.slide {
.image {
position: relative;
img {
width: 100% !important;
height: auto !important;
object-fit: cover;
}
.icon {
transition: 0.5s ease;
opacity: 0;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
-ms-transform: translate(-50%, -50%);
text-align: center;
span {
svg {
font-size: 30px;
color: #fff;
}
}
}
}
}
.image:hover .icon {
opacity: 1;
}
}
.image:after {
content: "";
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
background: rgba(211, 208, 208, 0.6);
opacity: 0;
transition: all 0.5s;
-webkit-transition: all 0.5s;
}
.image:hover:after {
opacity: 1;
}
Here's the link of demo (kindly see just above the footer section) for your reference.
Thank you for any help.
For draggle Slider there is a very lightweight JS Carousel package - siema
It is a great, lightweight carousel that is made with JS. There are also other packages built on top of this purely made for React.
In your case, I would offer to try out react-siema.
With it, you can simply use the carousel like that and it will be draggable by default. Plus, no need to load any css.

Conditional rendering + React

i tried making a method that holds the previous state, and changes back to the the previous state on click. Yet I checked if the method was working, and it was properly changing between true and false.
Yet, when I do a ternary operator in the className, it stays as the true value, and does not let me toggle between two classes. The first being the regular border, and the second having the position absolute with the checkmark to indicate it was selected. Even when I check dev tools, 'checkmark' is the className but nothing changes onClick...
import React from 'react';
import './Questions.css'
import girl_sweat from './girl_sweat.jpg'
class Questions extends React.Component {
constructor(props){
super(props);
this.state = {
isChoiceClicked: false
}
this.handleChoice = this.handleChoice.bind(this);
}
handleChoice(){
this.setState(prevState => ({isChoiceClicked: !prevState.isChoiceClicked}));
}
render(){
const isChoiceClicked = this.state;
return <div className="banner_column">
<div className="banner_column_1"><img src={girl_sweat}/></div>
<div className="banner_column_2"><div className="survey_enter"><h2 className="title">What are you interested in?</h2>
<p className="description">Select up to <strong>3 areas</strong></p>
<div className="choices">
<div className={`choice_container ${isChoiceClicked ? 'checkmark': 'null'}`} onChange={this.handleChoice}><h5>Yoga</h5><p className="activities">Vinyasa, Ashtanga, Kundalini, Hatha, Restorative, Prenatal</p></div>
<div className={`choice_container ${isChoiceClicked ? 'checkmark': 'choice_container'}`} onChange={this.handleChoice}><h5>Fitness</h5><p className="activities">Strength, Barre, Pilates, HIIT, Core, Stretching</p></div>
<div className={`choice_container ${isChoiceClicked ? 'checkmark': 'choice_container'}`} onChange={this.handleChoice}><h5>Mindfullness</h5><p className="activities">Meditation, Breathwork, Sound Bath, Yoga Nidra</p></div>
<div className={`choice_container ${isChoiceClicked ? 'checkmark': 'choice_container'}`} onChange={this.handleChoice}><h5>Skills</h5><p className="activities">Handstands, Arm Balances, Flexibility, Mobility</p></div>
</div>
<div className="next"><button className="next_question">next question</button></div>
</div>
</div>
</div>
}
}
export default Questions; ```
.choice_container {
margin: 0 auto;
width: 250px;
padding: 1rem;
border: solid 0.5px black;
position: relative;
}
.choice_container .checkmark {
display: hidden;
position: absolute;
border: solid 2px black;
right: -8px;
top: -8px;
width: 20px;
height: 20px;
border-radius: 50%;
background-color: #000;
color: #fff;
content: "✓";
}```
Even when I check dev tools, 'checkmark' is the className but nothing changes onClick
The function you activate should be onClick rather than onChange.
Usually onChange can be used in <input> and <select>. However, if you are using div, using onChange seems to be a problem.
<div className={`choice_container ${isChoiceClicked ? 'checkmark': 'null'}`} onClick={this.handleChoice}><h5>Yoga</h5><p className="activities">Vinyasa, Ashtanga, Kundalini, Hatha, Restorative, Prenatal</p></div>
Besides, I guess you wanna destructure from this.state. Therefore, you can do the following thing.
const isChoiceClicked = this.state;
const { isChoiceClicked } = this.state;

React body scroll lock issue on IOS

I'm literally fighting in finding a clean solution to the scroll issue in the IOS devices. In my App.js i've simply the background body and a modal with some contents. When the modal is shown i'd like to block the scroll in the background (myBodyContent) and still let the scroll in the modal component. I'm quite new to both javascript and React and this not helping me at all.
The cleanest solution (according to me) i was able to find is the body-scroll-lock package but it seems i'm not able to successfully use it. here is my code:
App.js
class App extends Component {
targetRef = React.createRef();
targetElement = null;
constructor(props) {
super(props);
}
componentDidMount() {
this.targetElement = this.targetRef.current;
disableBodyScroll(this.targetElement);
}
render() {
const myModal = (
<Modal ref={this.targetRef}>
// my long content here
</Modal>);
return (
<React.Fragment>
{myModal}
<Layout>
<myBodyContent>
</Layout>
</React.Fragment>
);
}
}
Modal.js
class Modal extends Component {
shouldComponentUpdate(nextProps, nextState){
return (nextProps.show !== this.props.show)
}
render () {
return (
<div>
<Auxi>
<Backdrop
show = {this.props.show}
clicked = {this.props.modalClosed}
/>
<div className={style.Modal}
style={{
transform: this.props.show ? 'translateY(0)' : 'translateY(-100vh)', // vh is special unit for outside screen
opacity: this.props.show ? '1': '0'
}}>
{this.props.children}
</div>
</Auxi>
</div>
);
}
}
Modal css
.Modal {
position: fixed;
z-index: 500;
background-color: white;
width: 80%;
overflow-y: hidden;
overflow: auto;
padding-right: 15px; /* Avoid width reflow */
border: 1px solid #ccc;
box-shadow: 1px 1px 1px black;
padding: 16px;
top: 5%;
left: 5%;
box-sizing: content-box;
transition: all 0.3s ease-out;
}
#media (min-width: 600px) {
.Modal {
width: 80%;
height: 80%;
left: 10%;
top: 10%
}
}
With the above code, simply everything is locked and i cannot scroll neither the modal nor the myBodyContent.
Can you help me understanding what i'm doing wrong? Or suggest me some other ways to achieve the same result?
Thanks in advance for your help.
You don't have targetElement (it's null) inside App componentDidMount because you try to set ref for React component but not HTML element.
To fix this you need to forward ref inside Modal component like that:
const myModal = (
<Modal forwardedRef={this.targetRef}>
// my long content here
</Modal>
);
and then :
class Modal extends Component {
shouldComponentUpdate(nextProps, nextState){
return (nextProps.show !== this.props.show)
}
render () {
return (
<div ref={this.props.forwardedRef}>
<Auxi>
<Backdrop
show = {this.props.show}
clicked = {this.props.modalClosed}
/>
<div className={style.Modal}
style={{
transform: this.props.show ? 'translateY(0)' : 'translateY(-100vh)', // vh is special unit for outside screen
opacity: this.props.show ? '1': '0'
}}>
{this.props.children}
</div>
</Auxi>
</div>
);
}
}
Thanks Max, i've tried but unfortunately the result is the same. I've also tried to enclose the Modal in a div directly in the App.js and apply the ref directly there without passing it as props...but it's the same. No way to scroll anything.

Design Bootstrap dynamic nav tabs component

I want to design a dynamic nav tabs component. when the card is clicked relevant tab is shown, with the connection arrow and border-color green.
sample code or a suggestion would be much helpful
.
You can use accordion by bootstrap. Use css flexbox to horizontally align the tabs next to each other and bind a javascript method that changes css color properties (arrow, green color) on clicking.
Here is the link - https://getbootstrap.com/docs/4.0/components/collapse/
Here is how you can do :
.js :
import React, { Component } from "react";
import { render } from "react-dom";
import "./style.css";
const App = () => {
const selectBlock = (e) => {
e.target.classList.toggle('selected');
}
return (
<div className="block" onClick={(e) => {selectBlock(e)}}>
<div>Here is the block</div>
<div className="arrow">
<FakeArrow />
</div>
</div>
);
};
const FakeArrow = () => {
return (
<div>
<span className="arrow-down-border" />
<span className="arrow-down" />
</div>
);
};
render(<App />, document.getElementById("root"));
.css :
.block {
position: relative;
width: 150px;
height: 50px;
text-align: center;
border: 2px solid black;
}
.arrow {
display: none;
}
.block.selected {
border: 2px solid #99d32c;
}
.block.selected .arrow {
display: block;
}
/* You need to fake the arrow border with another arrow behind */
.arrow-down-border {
position: absolute;
bottom: -20px;
left: 55px; /* 150px (main block) / 2 -20px (size of the triangle)*/
width: 0;
height: 0;
border-left: 20px solid transparent;
border-right: 20px solid transparent;
border-top: 20px solid #99d32c;
}
.arrow-down{
position: absolute;
bottom: -17px;
left: 58px; /* 150px (main block) / 2 -17px (size of the triangle)*/
width: 0;
height: 0;
border-left: 17px solid transparent;
border-right: 17px solid transparent;
border-top: 17px solid #ffffff;
}
Here is the repro on Stackblitz.
Of course this is just an example, you have to set a color for the arrows so my advice would be to do it with constants or props. Same thing for the position and others functionality you can add to the FakeArrow component.
Now, it would be waaaayy easier to manage it with an image if you really need a border (this is the tricky part in your requirement), or a simple arrow without border.
You can take a look at this post, it's the same question actually, i used a slightly different way to do it with css, but the result seems to be the same.

Resources