react-beautiful-horizontal-timeline
Version:
* We offer Horizontal **Timeline** with your costumize. * Layouts will work on **Any** device, big or small. * Mobiles support **Swipe**. * Ability to **Style** timeline as you want.
198 lines (181 loc) • 8.05 kB
JavaScript
import React, { useState, useEffect } from 'react';
import './card.css';
import { useSwipeable } from "react-swipeable";
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faChevronCircleRight, faChevronCircleLeft } from '@fortawesome/free-solid-svg-icons';
export function Timeline({
myList,
labelWidth,
amountMove,
lineColor,
darkMode,
eventTextAlignCenter,
showSlider,
arrowsSize
}) {
const [positionLeft, setpositionLeft] = useState(0);
const [positionAllowed, setpositionAllowed] = useState(0);
const [rightBtnEnable, setrightBtnEnable] = useState(true);
const [prevIdx, setprevIdx] = useState(-1);
const [rightToLeft, setrightToLeft] = useState(null);
const [curStatus, setcurStatus] = useState(myList && myList[0] && Object.values(myList[0])[0]);
const [curIdx, setcurIdx] = useState(0);
const checkIfNeedToDisableRightButton = (leftPosition) => {
if ((leftPosition * -1) >= positionAllowed) {//chack if its my last time i can click on right arrow, if yes, this loop shoud disable right arrow btn
setpositionLeft(-positionAllowed);//set the maximum position that i can give to the axis
setrightBtnEnable(false);//disable right arrow
return true;
} else {// i still can click on right arrow btn
setrightBtnEnable(true);
return false;
}
};
const moveAxis = (direction, amount) => {
let leftPosition;
if (direction === "right") {
leftPosition = positionLeft - amount; // calculate my left position after click arrow
let isNeedDisable = checkIfNeedToDisableRightButton(leftPosition);//check if i need to disable my right arrow
if (isNeedDisable) { return; }
} else {
leftPosition = positionLeft + amount;
setrightBtnEnable(true);// after i clicked on left arrow, right arrow should be enabled for sure
if (leftPosition > 0) {// check if its my last click on left arrow
setpositionLeft(0);
return;
}
}
setpositionLeft(leftPosition);
};
const resizeListener = () => {
window.addEventListener("resize", calcAfterResize);
};
const calcAfterResize = () => {
calcPostionSlideLeft();
};
useEffect(() => {
calcPostionSlideLeft();
resizeListener();
return () => {
window.removeEventListener("resize", calcAfterResize);
};
}, [positionLeft]);
const calcPostionSlideLeft = () => {//calculate how many px i can move my axis
let positionAllowed = document.getElementById("myAxis").getClientRects()[0].width - document.getElementById("axisWrapper").getClientRects()[0].width;
setpositionAllowed(positionAllowed);
};
const handlers = useSwipeable({
onSwiped: (eventData) => {
if (eventData.deltaX < 0) {
moveAxis('right', eventData.deltaX * -1);
} else {
moveAxis('left', eventData.deltaX);
}
}
});
return (
<div className="wrapperAll">
{positionLeft === 0 ? <FontAwesomeIcon
icon={faChevronCircleLeft}
size={arrowsSize === "sm" || !arrowsSize ? '2x' : (arrowsSize === "med" ? "3x" : "4x")}
id="leftArrow"
style={{
color: "grey",
borderColor: "grey"
}}
className=" disabledBtn "
/> : <FontAwesomeIcon
icon={faChevronCircleLeft}
size={arrowsSize === "sm" || !arrowsSize ? '2x' : (arrowsSize === "med" ? "3x" : "4x")}
id="leftArrow"
onClick={() => moveAxis('left', amountMove)}
style={{
color: lineColor,
borderColor: lineColor
}}
className=" enableBtn "
/>
}
<div className="axisWrapper" id="axisWrapper"
{...handlers}
>
<div
className={`axis ${positionAllowed <= 0 ? "notEnoghEvents" : ""}`}
id="myAxis"
style={{
left: `${positionLeft}px`,
borderTop: `2px solid ${lineColor}`,
}}
>
{myList && myList.map((val, index) => {
return <div
className="specificEvent"
id="specificEvent"
style={{
width: `${labelWidth}px`,
color: `${darkMode ? "#fff" : "unset"}`,
textAlign: `${eventTextAlignCenter ? "center" : "unset"}`
}}
key={index}
onClick={() => {
setcurIdx(index);
setprevIdx(curIdx);
setcurStatus('');
setrightToLeft(index === curIdx ? null : (index > curIdx ? true : false));
setTimeout(() => {
setprevIdx(curIdx);
setcurStatus(myList[index].name);
}, 0);
}}
>
<div
className="dot"
style={{
left: `${labelWidth / 2}px`,
background: lineColor
}}
></div>
{Object.values(val).map((value, index) => {
return <div key={index} className="descriptionEventDetails">{value}</div>;
})}
</div>;
})}
</div>
</div>
{
positionAllowed > 0 && rightBtnEnable ? <FontAwesomeIcon
icon={faChevronCircleRight}
size={arrowsSize === "sm" || !arrowsSize ? '2x' : (arrowsSize === "med" ? "3x" : "4x")}
id="rightArrow"
style={{
color: lineColor,
borderColor: lineColor
}}
onClick={() => moveAxis('right', amountMove)}
className=" enableBtn "
/> :
<FontAwesomeIcon
icon={faChevronCircleRight}
size={arrowsSize === "sm" || !arrowsSize ? '2x' : (arrowsSize === "med" ? "3x" : "4x")}
id="rightArrow"
style={{
color: "grey",
borderColor: "grey"
}}
className=" disabledBtn "
/>
}
{showSlider && <div className="wrapperEventCurrent">
{curStatus && <span
className="currentEventToShow"
style={{
animationName: `${rightToLeft === null ? "top-to-bottom" : (rightToLeft ? "right-to-left" : "left-to-right")}`,
color: `${darkMode ? "#fff" : "unset"}`,
borderLeft: `2px solid ${lineColor}`
}}>
{curStatus}
</span>}
</div>
}
</div>
);
}