"use client";
import { motion } from "motion/react";
import { memo, useEffect, useMemo, useState } from "react";
import { createPortal } from "react-dom";
import { cn } from "@/lib/utils";
import { useChart, useChartStable } from "./chart-context";
export interface BarYAxisProps {
/** Whether to show all labels or skip some for dense data. Default: true */
showAllLabels?: boolean;
/** Maximum number of labels to show. Default: 20 */
maxLabels?: number;
}
interface BarYAxisLabelProps {
label: string;
y: number;
bandHeight: number;
isHovered: boolean;
}
function BarYAxisLabel({
label,
y,
bandHeight,
isHovered,
}: BarYAxisLabelProps) {
return (
{label}
);
}
export function BarYAxis(props: BarYAxisProps) {
const { containerRef, barScale } = useChartStable();
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
}, []);
const container = containerRef.current;
if (!(mounted && container)) {
return null;
}
if (!barScale) {
return null;
}
return ;
}
const BarYAxisInner = memo(function BarYAxisInner({
showAllLabels = true,
maxLabels = 20,
container,
}: BarYAxisProps & { container: HTMLDivElement }) {
const { margin, barScale, bandWidth, barXAccessor, data, hoveredBarIndex } =
useChart();
// Generate labels for each bar
const labelsToShow = useMemo(() => {
if (!(barScale && bandWidth && barXAccessor)) {
return [];
}
const allLabels = data.map((d, i) => {
const label = barXAccessor(d);
const bandY = barScale(label) ?? 0;
// Center the label vertically within the band
const y = bandY + margin.top;
return { label, y, bandHeight: bandWidth, index: i };
});
// If showAllLabels is true or we have fewer than maxLabels, show all
if (showAllLabels || allLabels.length <= maxLabels) {
return allLabels;
}
// Otherwise, skip some labels to avoid crowding
const step = Math.ceil(allLabels.length / maxLabels);
return allLabels.filter((_, i) => i % step === 0);
}, [
barScale,
bandWidth,
barXAccessor,
data,
margin.top,
showAllLabels,
maxLabels,
]);
return createPortal(
{labelsToShow.map((item) => (
))}
,
container
);
});
BarYAxis.displayName = "BarYAxis";
export default BarYAxis;