Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion js/packages/react-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"type": "module",
"name": "@crayonai/react-ui",
"license": "MIT",
"version": "0.9.15",
"version": "0.9.16",
"description": "Component library for Generative UI SDK",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,10 @@ const AreaChartCondensedComponent = <T extends AreaChartData>({
if (data.length === 0) {
return 0;
}
return chartContainerWidth / data.length;
}, [chartContainerWidth, data]);
// Use passed width if available, otherwise use observed chartContainerWidth
const chartWidth = width ?? chartContainerWidth;
return chartWidth / data.length;
}, [width, chartContainerWidth, data]);

const { angle: calculatedAngle, height: xAxisHeight } = useAutoAngleCalculation(
maxLabelWidth,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,14 @@ export interface BarChartCondensedProps<T extends BarChartData> {
className?: string;
height?: number;
width?: number;
/** Maximum bar width in pixels. Prevents bars from becoming too wide. Default: 12 */
maxBarWidth?: number;
}

const BAR_WIDTH = 12;
// Default maximum bar width - prevents bars from becoming too wide with sparse data
const DEFAULT_MAX_BAR_WIDTH = 12;

// Layout constants
const BAR_GAP = 10;
const BAR_CATEGORY_GAP = "20%";
const BAR_INTERNAL_LINE_WIDTH = 1;
Expand All @@ -87,6 +92,7 @@ const BarChartCondensedComponent = <T extends BarChartData>({
className,
height = CHART_HEIGHT,
width,
maxBarWidth = DEFAULT_MAX_BAR_WIDTH,
}: BarChartCondensedProps<T>) => {
const printContext = usePrintContext();
isAnimationActive = printContext ? false : isAnimationActive;
Expand All @@ -106,8 +112,10 @@ const BarChartCondensedComponent = <T extends BarChartData>({
if (data.length === 0) {
return 0;
}
return chartContainerWidth / data.length;
}, [chartContainerWidth, data]);
// Use passed width if available, otherwise use observed chartContainerWidth
const chartWidth = width ?? chartContainerWidth;
return chartWidth / data.length;
}, [chartContainerWidth, data, width]);

const { angle: calculatedAngle, height: xAxisHeight } = useAutoAngleCalculation(
maxLabelWidth,
Expand Down Expand Up @@ -201,6 +209,39 @@ const BarChartCondensedComponent = <T extends BarChartData>({
return width ?? containerWidth;
}, [width, containerWidth]);

// Calculate explicit chart width when width prop is provided
// This allows Recharts to calculate bar dimensions on first render
const explicitChartWidth = useMemo(() => {
if (!width) return undefined;
// Subtract Y-axis width and margins to get the actual chart area width
const yAxisSpace = showYAxis ? yAxisWidth : 0;
return width - yAxisSpace - chartMargin.left - chartMargin.right;
}, [width, showYAxis, yAxisWidth, chartMargin.left, chartMargin.right]);

// Calculate optimal bar width based on available space
// Only applies maximum constraint - Recharts handles thin bars automatically
const calculatedBarWidth = useMemo(() => {
// Use explicitChartWidth if available, otherwise fall back to chartContainerWidth
const availableWidth = explicitChartWidth ?? chartContainerWidth;

// If no width available, return undefined and let Recharts auto-size
if (!availableWidth || availableWidth === 0 || data.length === 0) {
return undefined;
}

// Calculate space per category (Recharts handles gaps automatically via barGap and barCategoryGap props)
const spacePerCategory = availableWidth / data.length;

// For grouped charts, multiple bars share the category space
const barsPerCategory = variant === "stacked" ? 1 : dataKeys.length;

// Simple division - let Recharts apply gaps via barGap and barCategoryGap props
const barWidth = spacePerCategory / barsPerCategory;

// Only apply maximum constraint, let Recharts handle thin bars automatically
return Math.min(maxBarWidth, barWidth);
}, [explicitChartWidth, chartContainerWidth, data.length, dataKeys.length, variant, maxBarWidth]);

// Handle mouse events for bar hovering
const handleChartMouseMove = useCallback((state: any) => {
if (state && state.activeLabel !== undefined) {
Expand Down Expand Up @@ -231,15 +272,16 @@ const BarChartCondensedComponent = <T extends BarChartData>({

// Observe container width for legend
useEffect(() => {
// Only set up ResizeObserver if width is not provided
if (width || !containerRef.current || !chartContainerRef.current) {
// Always set up ResizeObserver for chartContainerRef to get accurate bar width calculations
if (!chartContainerRef.current) {
return () => {};
}

const resizeObserver = new ResizeObserver((entries) => {
// there is only one entry in the entries array because we are observing the chart container
for (const entry of entries) {
if (entry.target === containerRef.current) {
if (entry.target === containerRef.current && !width) {
// Only observe containerRef if width is not provided
setContainerWidth(entry.contentRect.width);
}
if (entry.target === chartContainerRef.current) {
Expand All @@ -248,9 +290,14 @@ const BarChartCondensedComponent = <T extends BarChartData>({
}
});

resizeObserver.observe(containerRef.current);
// Always observe chartContainerRef
resizeObserver.observe(chartContainerRef.current);

// Only observe containerRef if width is not provided
if (!width && containerRef.current) {
resizeObserver.observe(containerRef.current);
}

return () => {
resizeObserver.disconnect();
};
Expand Down Expand Up @@ -335,8 +382,8 @@ const BarChartCondensedComponent = <T extends BarChartData>({
fill={color}
stackId={variant === "stacked" ? "a" : undefined}
isAnimationActive={isAnimationActive}
maxBarSize={BAR_WIDTH}
barSize={BAR_WIDTH}
maxBarSize={calculatedBarWidth}
barSize={calculatedBarWidth}
shape={(props: any) => {
const { payload, value, dataKey } = props;

Expand Down Expand Up @@ -378,6 +425,7 @@ const BarChartCondensedComponent = <T extends BarChartData>({
barInternalLineColor,
hoveredCategory,
categoryKey,
calculatedBarWidth,
]);

return (
Expand All @@ -404,10 +452,13 @@ const BarChartCondensedComponent = <T extends BarChartData>({
<div className="crayon-bar-chart-condensed" ref={chartContainerRef}>
<ChartContainer
config={chartConfig}
style={{ width: "100%", height: effectiveHeight }}
style={{
width: explicitChartWidth ? `${explicitChartWidth}px` : "100%",
height: effectiveHeight,
}}
rechartsProps={{
width: "100%",
height: "100%",
width: explicitChartWidth ?? "100%",
height: effectiveHeight,
}}
>
<RechartsBarChart
Expand All @@ -421,6 +472,8 @@ const BarChartCondensedComponent = <T extends BarChartData>({
onMouseMove={handleChartMouseMove}
onMouseLeave={handleChartMouseLeave}
onClick={onBarClick}
width={explicitChartWidth}
height={effectiveHeight}
>
{grid && cartesianGrid()}

Expand Down
Loading