I couldn't find anything, including on bit.dev, so I threw together a quick template component which I think does some of the heavy-lifting of what you are trying to do. Here is an example screenshot.
Here is the CodeSandbox and the source for the component.
function Progress({
steps = [0, 5, 10, 20],
width = 300,
value = Math.min(steps ?? []) ?? 0
}) {
const filledAmount = (index) => {
return Math.max(
Math.min(
(100 * (value - steps[index])) / (steps[index + 1] - steps[index]),
100
),
0
);
};
const amountComplete = (100 * value) / (steps[steps.length - 1] - steps[0]);
return (
<div className="progress-container" style={width ? { width } : {}}>
<div className="progress-top-row">
<p
className="progress-text"
style={{
marginLeft: `${amountComplete}%`,
transform: "translateX(-50%)"
}}
>
{value}
</p>
</div>
<div
className="progress-middle-row"
style={width ? { width: width } : {}}
>
{[...steps].slice(1).map((s, i) => (
<div key={s} className="bar-slice">
<div
className="filled-slice"
style={{ width: `${filledAmount(i)}%` }}
></div>
</div>
))}
</div>
<div className="progress-bottom-row">
{steps.map((s) => (
<div key={s} className="progress-label">
<p>{s}</p>
</div>
))}
</div>
</div>
);
}
There are definitely some areas to refine according to your coding standards (and putting more time into it than I will) and your desired end state. I hope it works well for what you are trying to accomplish.