<div class="container"></div>
.tag:first-of-type {
border-radius: 50px 0px 0px 50px;
}
.tag:last-of-type {
border-radius: 0px 50px 50px 0px;
}
.tag:last-of-type>.slider-button {
display:none !important;
}
span{
font-family:sans-serif !important;
}
//ES6 const, let
//ES6 Destructuring
const { Component, useRef, Fragment, useState } = React;
// import React,{ useState, useRef,Fragment } from 'react'
const _tags = [
{
name: "Action",
color: "red"
},
{
name: "Romance",
color: "purple"
},
{
name: "Comedy",
color: "orange"
},
{
name: "Horror",
color: "black"
}
];
const getPercentage = (containerWidth: number, distanceMoved: number) => {
return (distanceMoved / containerWidth) * 100;
};
interface TagSectionProps {
name: string;
color: string;
width: number;
onSliderSelect: (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
}
const TagSection = ({
name,
color,
width,
onSliderSelect
}: TagSectionProps) => {
return (
<div
className="tag"
style={{
...styles.tag,
background: color,
width: width + "%"
}}
>
<span style={styles.tagText}>{name}</span>
<span style={{ ...styles.tagText, fontSize: 12 }}>{width + "%"}</span>
<div
style={styles.sliderButton}
onPointerDown={onSliderSelect}
className="slider-button"
>
<img src={"https://animesonar.com/slider-arrows.svg"} height={"30%"} />
</div>
</div>
);
};
const TagSlider = () => {
const [widths, setWidths] = useState<number[]>(
new Array(_tags.length).fill(100 / _tags.length)
);
const [tags, setTags] = useState(_tags);
const TagSliderRef = useRef<HTMLDivElement>(null);
return (
<div
ref={TagSliderRef}
style={{
width: "100%",
display: "flex"
}}
>
{tags.map((tag, index) => (
<TagSection
width={widths[index]}
key={index}
noSliderButton={index === tags.length - 1}
name={tag.name}
onSliderSelect={(e) => {
e.preventDefault();
document.body.style.cursor = "ew-resize";
const startDragX = e.pageX;
const sliderWidth = TagSliderRef.current.offsetWidth;
const resize = (e: MouseEvent & TouchEvent) => {
e.preventDefault();
const endDragX = e.touches ? e.touches[0].pageX : e.pageX;
const distanceMoved = endDragX - startDragX;
const percentageMoved = getPercentage(sliderWidth, distanceMoved);
const _widths = widths.slice();
const prevPercentage = _widths[index];
const newPercentage = prevPercentage + percentageMoved;
_widths[index] = newPercentage;
setWidths(_widths);
};
window.addEventListener("pointermove", resize);
window.addEventListener("touchmove", resize);
const removeEventListener = () => {
window.removeEventListener("pointermove", resize);
window.removeEventListener("touchmove", resize);
};
const handleEventUp = (e: Event) => {
e.preventDefault();
document.body.style.cursor = "initial";
removeEventListener();
};
window.addEventListener("touchend", handleEventUp);
window.addEventListener("pointerup", handleEventUp);
}}
color={tag.color}
/>
))}
</div>
);
};
type StylesType = { [key: string]: React.CSSProperties };
const styles: StylesType = {
tag: {
padding: 20,
textAlign: "center",
position: "relative",
borderRightWidth: ".1em",
borderRightStyle: "solid",
borderRightColor: "white",
boxSizing: "border-box",
borderLeftWidth: ".1em",
borderLeftStyle: "solid",
borderLeftColor: "white"
},
tagText: {
color: "white",
fontWeight: 700,
userSelect: "none",
display: "block",
overflow: "hidden",
fontFamily: "serif"
},
sliderButton: {
width: "2em",
height: "2em",
backgroundColor: "white",
position: "absolute",
borderRadius: "2em",
right: "calc(-1.1em)",
top: 0,
display: "flex",
justifyContent: "center",
alignItems: "center",
bottom: 0,
margin: "auto",
zIndex: 10,
cursor: "ew-resize",
userSelect: "none"
}
};
ReactDOM.render(<TagSlider />, document.querySelector(".container"));
View Compiled
This Pen doesn't use any external CSS resources.