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.6",
"version": "0.9.7",
"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 @@ -23,6 +23,7 @@ import {
getWidthOfData,
getWidthOfGroup,
} from "../utils/AreaAndLine/AreaAndLineUtils";
import { getLineType } from "../utils/AreaAndLine/common";
import { PaletteName, useChartPalette } from "../utils/PalletUtils";
import {
get2dChartConfig,
Expand Down Expand Up @@ -64,7 +65,7 @@ const AreaChartComponent = <T extends AreaChartData>({
categoryKey,
theme = "ocean",
customPalette,
variant = "natural",
variant: areaChartVariant = "natural",
tickVariant = "multiLine",
grid = true,
icons = {},
Expand All @@ -81,6 +82,8 @@ const AreaChartComponent = <T extends AreaChartData>({
return getDataKeys(data, categoryKey as string);
}, [data, categoryKey]);

const variant = getLineType(areaChartVariant);

const { yAxisWidth, setLabelWidth } = useYAxisLabelWidth(data, dataKeys);

const widthOfGroup = useMemo(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
} from "../shared";
import { LabelTooltipProvider } from "../shared/LabelTooltip/LabelTooltip";
import { LegendItem } from "../types";
import { getLineType } from "../utils/AreaAndLine/common";
import { get2dChartConfig, getDataKeys, getLegendItems } from "../utils/dataUtils";
import { PaletteName, useChartPalette } from "../utils/PalletUtils";

Expand Down Expand Up @@ -53,7 +54,7 @@ const AreaChartCondensedComponent = <T extends AreaChartData>({
categoryKey,
theme = "ocean",
customPalette,
variant = "natural",
variant: areaChartVariant = "natural",
tickVariant = "singleLine",
grid = true,
icons = {},
Expand All @@ -70,6 +71,8 @@ const AreaChartCondensedComponent = <T extends AreaChartData>({
return getDataKeys(data, categoryKey as string);
}, [data, categoryKey]);

const variant = getLineType(areaChartVariant);

const { yAxisWidth, setLabelWidth } = useYAxisLabelWidth(data, dataKeys);

const maxLabelWidth = useMaxLabelWidth(data, categoryKey as string);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1059,6 +1059,90 @@ export const TickVariantComparison: Story = {
},
};

/**
* ## Super Condensed Bar Chart
*
* This story demonstrates the chart with many data points in a very narrow container,
* creating extremely thin bars. This tests the minimum bar width logic and the
* automatic removal of rounded corners for bars thinner than 7px.
*/
export const SuperCondensedStory: Story = {
name: "🔬 Super Condensed (Many Bars)",
args: {
data: [
{ month: "Jan '23", desktop: 150, mobile: 90, tablet: 60 },
{ month: "Feb '23", desktop: 280, mobile: 180, tablet: 100 },
{ month: "Mar '23", desktop: 220, mobile: 140, tablet: 80 },
{ month: "Apr '23", desktop: 180, mobile: 160, tablet: 90 },
{ month: "May '23", desktop: 250, mobile: 120, tablet: 70 },
{ month: "Jun '23", desktop: 300, mobile: 180, tablet: 110 },
{ month: "Jul '23", desktop: 350, mobile: 220, tablet: 130 },
{ month: "Aug '23", desktop: 400, mobile: 240, tablet: 150 },
{ month: "Sep '23", desktop: 450, mobile: 260, tablet: 170 },
{ month: "Oct '23", desktop: 500, mobile: 280, tablet: 190 },
{ month: "Nov '23", desktop: 550, mobile: 300, tablet: 210 },
{ month: "Dec '23", desktop: 600, mobile: 320, tablet: 230 },
{ month: "Jan '24", desktop: 620, mobile: 340, tablet: 250 },
{ month: "Feb '24", desktop: 640, mobile: 360, tablet: 270 },
{ month: "Mar '24", desktop: 680, mobile: 380, tablet: 290 },
{ month: "Apr '24", desktop: 700, mobile: 400, tablet: 310 },
{ month: "May '24", desktop: 720, mobile: 420, tablet: 330 },
{ month: "Jun '24", desktop: 750, mobile: 440, tablet: 350 },
{ month: "Jul '24", desktop: 780, mobile: 460, tablet: 370 },
{ month: "Aug '24", desktop: 800, mobile: 480, tablet: 390 },
{ month: "Sep '24", desktop: 820, mobile: 500, tablet: 410 },
{ month: "Oct '24", desktop: 850, mobile: 520, tablet: 430 },
{ month: "Nov '24", desktop: 880, mobile: 540, tablet: 450 },
{ month: "Dec '24", desktop: 900, mobile: 560, tablet: 470 },
] as any,
categoryKey: "month" as any,
theme: "ocean",
variant: "grouped",
tickVariant: "angled",
radius: 4,
grid: true,
isAnimationActive: false,
showYAxis: true,
height: 180,
},
render: (args: any) => (
<div>
<div
style={{
marginBottom: "16px",
padding: "12px",
background: "#f8f9fa",
borderRadius: "8px",
border: "1px solid #e9ecef",
width: "320px",
}}
>
<h4 style={{ margin: "0 0 8px 0", color: "#333" }}>🔬 Ultra Condensed View</h4>
<p style={{ margin: "0 0 12px 0", fontSize: "14px", color: "#666" }}>
24 months × 3 series = 72 bars in 320px width. Each bar is ~4px wide or less!
</p>
<ul style={{ margin: "0", paddingLeft: "20px", fontSize: "12px", color: "#666" }}>
<li>Bars {"<"} 7px wide = no rounded corners</li>
<li>Minimum bar width: 2px enforced</li>
<li>Angled labels prevent overlap</li>
<li>Internal lines hidden on thin bars</li>
</ul>
</div>
<Card style={{ width: "320px" }}>
<BarChartCondensed {...args} />
</Card>
</div>
),
parameters: {
docs: {
description: {
story:
"**Extreme density test** with 24 data points × 3 series (72 total bars) in a 320px container, making each bar approximately 4px wide or less. This demonstrates:\n\n- **Automatic corner removal**: Bars thinner than 7px automatically become square (no rounded corners)\n- **Minimum width enforcement**: Bars maintain a minimum width of 2px for visibility\n- **Grouped bar handling**: Multiple series create even thinner individual bars\n- **Label handling**: Angled labels prevent overlap in ultra-dense scenarios\n- **Internal line hiding**: The internal line is hidden when bars are too thin to display it properly\n\nThis represents an extreme edge case useful for:\n- Compact dashboard widgets\n- Sidebar sparkline-style analytics\n- Mobile-optimized views\n- High-density data visualization in limited space",
},
},
},
};

/**
* ## Responsive Behavior Demo
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
getWidthOfData,
getWidthOfGroup,
} from "../utils/AreaAndLine/AreaAndLineUtils";
import { getLineType } from "../utils/AreaAndLine/common";
import { PaletteName, useChartPalette } from "../utils/PalletUtils";
import {
get2dChartConfig,
Expand Down Expand Up @@ -63,7 +64,7 @@ export const LineChart = <T extends LineChartData>({
categoryKey,
theme = "ocean",
customPalette,
variant = "natural",
variant: lineChartVariant = "natural",
tickVariant = "multiLine",
grid = true,
icons = {},
Expand All @@ -81,6 +82,8 @@ export const LineChart = <T extends LineChartData>({
return getDataKeys(data, categoryKey as string);
}, [data, categoryKey]);

const variant = getLineType(lineChartVariant);

const { yAxisWidth, setLabelWidth } = useYAxisLabelWidth(data, dataKeys);

const widthOfGroup = useMemo(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
} from "../shared";
import { LabelTooltipProvider } from "../shared/LabelTooltip/LabelTooltip";
import { LegendItem } from "../types";
import { getLineType } from "../utils/AreaAndLine/common";
import { get2dChartConfig, getDataKeys, getLegendItems } from "../utils/dataUtils";
import { PaletteName, useChartPalette } from "../utils/PalletUtils";

Expand Down Expand Up @@ -54,7 +55,7 @@ const LineChartCondensedComponent = <T extends LineChartData>({
categoryKey,
theme = "ocean",
customPalette,
variant = "natural",
variant: lineChartVariant = "natural",
tickVariant = "singleLine",
grid = true,
icons = {},
Expand All @@ -72,6 +73,8 @@ const LineChartCondensedComponent = <T extends LineChartData>({
return getDataKeys(data, categoryKey as string);
}, [data, categoryKey]);

const variant = getLineType(lineChartVariant);

const { yAxisWidth, setLabelWidth } = useYAxisLabelWidth(data, dataKeys);

const maxLabelWidth = useMaxLabelWidth(data, categoryKey as string);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import clsx from "clsx";
import { useEffect, useMemo, useRef, useState } from "react";
import { Area, AreaChart as RechartsAreaChart, XAxis } from "recharts";
import { useId } from "../../../polyfills";
import { AreaChartVariant } from "../AreaChart/types";
import { ChartConfig, ChartContainer } from "../Charts";
import {
DATA_KEY,
getRecentDataThatFits,
transformDataForChart,
} from "../utils/AreaAndLine/MiniAreaAndLineUtils";
import { getLineType } from "../utils/AreaAndLine/common";
import { useChartPalette, type PaletteName } from "../utils/PalletUtils";
import { get2dChartConfig } from "../utils/dataUtils";
import { MiniAreaChartData } from "./types";
Expand All @@ -16,7 +18,7 @@ export interface MiniAreaChartProps {
data: MiniAreaChartData;
theme?: PaletteName;
customPalette?: string[];
variant?: "linear" | "natural" | "step";
variant?: AreaChartVariant;
opacity?: number;
isAnimationActive?: boolean;
onAreaClick?: (data: any) => void;
Expand All @@ -30,7 +32,7 @@ export const MiniAreaChart = ({
data,
theme = "ocean",
customPalette,
variant = "natural",
variant: areaChartVariant = "natural",
opacity = 0.5,
isAnimationActive = false,
onAreaClick,
Expand All @@ -42,6 +44,8 @@ export const MiniAreaChart = ({
const containerRef = useRef<HTMLDivElement>(null);
const [containerWidth, setContainerWidth] = useState<number>(0);

const variant = getLineType(areaChartVariant);

useEffect(() => {
if (!containerRef.current) {
return () => {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ import clsx from "clsx";
import { useEffect, useMemo, useRef, useState } from "react";
import { Line, LineChart as RechartsLineChart, XAxis } from "recharts";
import { ChartConfig, ChartContainer } from "../Charts";
import { LineChartVariant } from "../LineChart/types";
import {
DATA_KEY,
getRecentDataThatFits,
transformDataForChart,
} from "../utils/AreaAndLine/MiniAreaAndLineUtils";
import { getLineType } from "../utils/AreaAndLine/common";
import { useChartPalette, type PaletteName } from "../utils/PalletUtils";
import { get2dChartConfig } from "../utils/dataUtils";
import { MiniLineChartData } from "./types";
Expand All @@ -15,7 +17,7 @@ export interface MiniLineChartProps {
data: MiniLineChartData;
theme?: PaletteName;
customPalette?: string[];
variant?: "linear" | "natural" | "step";
variant?: LineChartVariant;
strokeWidth?: number;
isAnimationActive?: boolean;
onLineClick?: (data: any) => void;
Expand All @@ -28,7 +30,7 @@ export const MiniLineChart = ({
data,
theme = "ocean",
customPalette,
variant = "natural",
variant: lineChartVariant = "natural",
strokeWidth = 2,
isAnimationActive = true,
onLineClick,
Expand All @@ -39,6 +41,8 @@ export const MiniLineChart = ({
const containerRef = useRef<HTMLDivElement>(null);
const [containerWidth, setContainerWidth] = useState<number>(0);

const variant = getLineType(lineChartVariant);

useEffect(() => {
if (!containerRef.current) {
return () => {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,13 @@ const LineInBarShape: FunctionComponent<LineInBarShapeProps> = React.memo((props
return { rTL: 0, rTR: 0, rBL: 0, rBR: 0 };
}

// Check bar thickness and remove rounded corners if too thin
// For vertical bars: check width, for horizontal bars: check height
const barThickness = isVertical ? w : h;
if (barThickness < 7) {
return { rTL: 0, rTR: 0, rBL: 0, rBR: 0 };
}

// If radius is an array, apply specific radius to each corner
if (Array.isArray(r)) {
// The radius array is expected to be in the format [rTL, rTR, rBR, rBL].
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { AreaChartVariant, LineChartVariant } from "../..";

export const getLineType = (lineType: LineChartVariant | AreaChartVariant) => {
switch (lineType) {
case "linear":
return "linear";
case "natural":
return "monotone";
case "step":
return "step";
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,14 @@ export const FloatingDatePickerRenderer = ({
}) => {
const { isOpen, setIsOpen } = useDatePicker();
const menuRef = useRef<HTMLDivElement>(null);
const containerRef = useRef<HTMLDivElement>(null);

useEffect(() => {
if (!isOpen) return;

const handleInteraction = (e: MouseEvent | TouchEvent) => {
if (menuRef.current?.contains(e.target as Node)) {
const targetNode = e.target as Node;
if (menuRef.current?.contains(targetNode) || containerRef.current?.contains(targetNode)) {
return;
}
setIsOpen(false);
Expand All @@ -115,6 +117,7 @@ export const FloatingDatePickerRenderer = ({

return (
<div
ref={containerRef}
className={clsx("crayon-date-picker-renderer-floating-container", className)}
style={style}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,8 +232,8 @@ export const YearsDropdown = (
"crayon-date-picker-select-viewport",
botType === "mobile" && "crayon-date-picker-select-viewport-mobile",
)}
sideOffset={12}
alignOffset={-75}
sideOffset={0}
alignOffset={-135}
style={{
minHeight: `${containerHeight - 45}px`,
maxHeight: `${containerHeight - 45}px`,
Expand Down