diff --git a/src/components/area-chart/area-chart.stories.tsx b/src/components/area-chart/area-chart.stories.tsx
index 69de4b6f..3ad97839 100644
--- a/src/components/area-chart/area-chart.stories.tsx
+++ b/src/components/area-chart/area-chart.stories.tsx
@@ -4,7 +4,7 @@ import Label from '../label';
import Button from '../button';
import Badge from '../badge';
import Container from '../container';
-import { ArrowUpRight, ArrowUp } from 'lucide-react';
+import { ArrowUpRight, ArrowUp, AlertCircle } from 'lucide-react';
const areaChartData = [
{ month: 'January', sales: 186, expenses: 80 },
@@ -15,7 +15,21 @@ const areaChartData = [
{ month: 'June', sales: 214, expenses: 140 },
];
+// Data with large values to demonstrate Y-axis formatting
+const largeValuesData = [
+ { month: 'January', pageviews: 1200, sessions: 800 },
+ { month: 'February', pageviews: 2800, sessions: 1500 },
+ { month: 'March', pageviews: 5500, sessions: 2900 },
+ { month: 'April', pageviews: 8200, sessions: 4100 },
+ { month: 'May', pageviews: 14000, sessions: 6200 },
+ { month: 'June', pageviews: 18500, sessions: 8800 },
+];
+
+// Empty data for demonstrating custom no data component
+const emptyData: { month: string; sales: number; expenses: number }[] = [];
+
const dataKeys = [ 'sales', 'expenses' ];
+const largeDataKeys = [ 'pageviews', 'sessions' ];
const chartDataIteractive = [
{ date: '2024-04-01', desktop: 222, mobile: 150 },
@@ -121,6 +135,29 @@ const colors = [
// Custom tick formatter function for months
const monthFormatter = ( value: string ) => value.slice( 0, 3 );
+// Custom Y-axis formatter function to display values in K/M format
+const yAxisFormatter = ( value: number ) => {
+ if ( value >= 1000000 ) {
+ return `${ ( value / 1000000 ).toFixed( 1 ) }M`;
+ }
+ if ( value >= 1000 ) {
+ return `${ ( value / 1000 ).toFixed( 1 ) }K`;
+ }
+ return value.toString();
+};
+
+// Custom No Data Component
+const CustomNoDataComponent = () => (
+
+
+
No data found
+
+ There is no data available for this chart at the moment. Try
+ adjusting your filters or check back later.
+
+
+);
+
const monthFormatterInteractive = ( value: string ) => {
const date = new Date( value );
return date.toLocaleDateString( 'en-US', {
@@ -187,7 +224,83 @@ export const AreaChartInteractive: Story = {
},
};
+export const AreaChartWithFormattedYAxis: Story = {
+ args: {
+ chartWidth: 600,
+ chartHeight: 300,
+ data: largeValuesData,
+ dataKeys: largeDataKeys,
+ colors: [
+ { stroke: '#3b82f6', fill: '#BFDBFE' },
+ { stroke: '#f97316', fill: '#FFEDD5' },
+ ],
+ variant: 'solid',
+ showXAxis: true,
+ xAxisDataKey: 'month',
+ showYAxis: true,
+ tickFormatter: monthFormatter,
+ yAxisTickFormatter: yAxisFormatter,
+ showLegend: true,
+ areaChartWrapperProps: {
+ margin: {
+ left: 35,
+ right: 14,
+ top: 6,
+ bottom: 6,
+ },
+ },
+ },
+};
+
+export const AreaChartGradientWithFormattedYAxis: Story = {
+ args: {
+ chartWidth: 600,
+ chartHeight: 300,
+ data: largeValuesData,
+ dataKeys: largeDataKeys,
+ colors: [
+ { stroke: '#3b82f6', fill: '#BFDBFE' },
+ { stroke: '#f97316', fill: '#FFEDD5' },
+ ],
+ variant: 'gradient',
+ showXAxis: true,
+ xAxisDataKey: 'month',
+ showYAxis: true,
+ tickFormatter: monthFormatter,
+ yAxisTickFormatter: yAxisFormatter,
+ showLegend: true,
+ areaChartWrapperProps: {
+ margin: {
+ left: 35,
+ right: 14,
+ top: 6,
+ bottom: 6,
+ },
+ },
+ },
+};
+
+export const AreaChartWithCustomNoDataComponent: Story = {
+ args: {
+ chartWidth: 600,
+ chartHeight: 300,
+ data: emptyData,
+ dataKeys,
+ colors,
+ variant: 'solid',
+ showXAxis: true,
+ xAxisDataKey: 'month',
+ showYAxis: true,
+ noDataComponent: ,
+ },
+};
+
AreaChartInteractive.storyName = 'Area Chart Gradient with Legend';
+AreaChartWithFormattedYAxis.storyName = 'Area Chart with Formatted Y-Axis';
+AreaChartGradientWithFormattedYAxis.storyName =
+ 'Area Chart Gradient with Formatted Y-Axis';
+AreaChartWithCustomNoDataComponent.storyName =
+ 'Area Chart with Custom No Data Component';
type Story1 = StoryFn;
diff --git a/src/components/area-chart/area-chart.tsx b/src/components/area-chart/area-chart.tsx
index a4b24b98..2255206f 100644
--- a/src/components/area-chart/area-chart.tsx
+++ b/src/components/area-chart/area-chart.tsx
@@ -1,4 +1,4 @@
-import { useEffect, useState } from 'react';
+import { useEffect, useState, type ReactNode } from 'react';
import {
AreaChart as AreaChartWrapper,
Area,
@@ -14,6 +14,13 @@ import ChartTooltipContent from './chart-tooltip-content';
import Label from '../label';
import type { CategoricalChartProps } from 'recharts/types/chart/generateCategoricalChart';
+// Default color constants
+const DEFAULT_FONT_COLOR = '#6B7280';
+const DEFAULT_AREA_COLORS = [
+ { stroke: '#2563EB', fill: '#BFDBFE' },
+ { stroke: '#38BDF8', fill: '#BAE6FD' },
+];
+
interface DataItem {
[key: string]: number | string; // Adjust based on your data structure
}
@@ -56,9 +63,18 @@ interface AreaChartProps {
/** Whether to display the ``, adding horizontal and vertical grid lines. */
showCartesianGrid?: boolean;
- /** A function used to format the ticks on the axes, e.g., for formatting dates or numbers. */
+ /** A function used to format the ticks on the x-axis, e.g., for formatting dates or numbers. */
+ xAxisTickFormatter?: ( value: string ) => string;
+
+ /**
+ * A function used to format the ticks on the x-axis, e.g., for formatting dates or numbers.
+ * @deprecated Use `xAxisTickFormatter` instead.
+ */
tickFormatter?: ( value: string ) => string;
+ /** A function used to format the ticks on the y-axis, e.g., for converting 1000 to 1K. */
+ yAxisTickFormatter?: ( value: number ) => string;
+
/** The key in the data objects representing values for the x-axis. This is used to access the x-axis values from each data entry. */
xAxisDataKey?: string;
@@ -85,6 +101,12 @@ interface AreaChartProps {
CategoricalChartProps,
'width' | 'height' | 'data'
>;
+
+ /**
+ * Custom component to display when no data is available.
+ * If not provided, a default "No data available" message will be displayed.
+ */
+ noDataComponent?: ReactNode;
}
const AreaChart = ( {
@@ -99,11 +121,13 @@ const AreaChart = ( {
tooltipLabelKey,
showLegend = true,
showCartesianGrid = true,
+ xAxisTickFormatter,
tickFormatter,
+ yAxisTickFormatter,
xAxisDataKey,
yAxisDataKey,
xAxisFontSize = 'sm', // sm, md, lg
- xAxisFontColor = '#6B7280',
+ xAxisFontColor = DEFAULT_FONT_COLOR,
chartWidth = 350,
chartHeight = 200,
areaChartWrapperProps = {
@@ -114,17 +138,12 @@ const AreaChart = ( {
bottom: 6,
},
},
+ noDataComponent,
}: AreaChartProps ) => {
const [ width, setWidth ] = useState( chartWidth );
const [ height, setHeight ] = useState( chartHeight );
- // Default colors
- const defaultColors: Color[] = [
- { stroke: '#2563EB', fill: '#BFDBFE' },
- { stroke: '#38BDF8', fill: '#BAE6FD' },
- ];
-
- const appliedColors = colors.length > 0 ? colors : defaultColors;
+ const appliedColors = colors.length > 0 ? colors : DEFAULT_AREA_COLORS;
useEffect( () => {
setWidth( chartWidth );
@@ -167,9 +186,11 @@ const AreaChart = ( {
if ( ! data || data.length === 0 ) {
return (
-
+ noDataComponent || (
+
+ )
);
}
@@ -182,7 +203,7 @@ const AreaChart = ( {
tickLine={ false }
axisLine={ false }
tickMargin={ 8 }
- tickFormatter={ tickFormatter }
+ tickFormatter={ xAxisTickFormatter || tickFormatter }
tick={ {
fontSize: fontSizeVariant,
fill: xAxisFontColor,
@@ -195,6 +216,7 @@ const AreaChart = ( {
tickLine={ false }
axisLine={ false }
tickMargin={ 8 }
+ tickFormatter={ yAxisTickFormatter }
tick={ {
fontSize: fontSizeVariant,
fill: xAxisFontColor,
diff --git a/src/components/line-chart/line-chart.stories.tsx b/src/components/line-chart/line-chart.stories.tsx
index c270c89e..ea1ce637 100644
--- a/src/components/line-chart/line-chart.stories.tsx
+++ b/src/components/line-chart/line-chart.stories.tsx
@@ -29,8 +29,22 @@ const biaxialChartData = [
{ month: 'June', visits: 214, revenue: 6800 },
];
+// Data with large values to demonstrate Y-axis formatting
+const largeValuesData = [
+ { month: 'January', pageviews: 1200, users: 500 },
+ { month: 'February', pageviews: 2500, users: 1200 },
+ { month: 'March', pageviews: 5000, users: 2300 },
+ { month: 'April', pageviews: 7800, users: 3600 },
+ { month: 'May', pageviews: 12000, users: 4800 },
+ { month: 'June', pageviews: 15000, users: 6500 },
+];
+
+// Empty data for demonstrating custom no data component
+const emptyData: { month: string; desktop: number }[] = [];
+
const dataKeys = [ 'desktop', 'mobile' ];
const biaxialDataKeys = [ 'visits', 'revenue' ];
+const largeDataKeys = [ 'pageviews', 'users' ];
const colors = [ { stroke: '#2563EB' }, { stroke: '#38BDF8' } ];
@@ -48,6 +62,42 @@ export default meta;
// Custom tick formatter function for months
const monthFormatter = ( value: string ) => value.slice( 0, 3 );
+// Custom Y-axis formatter function to display values in K/M format
+const yAxisFormatter = ( value: number ) => {
+ if ( value >= 1000000 ) {
+ return `${ ( value / 1000000 ).toFixed( 1 ) }M`;
+ }
+ if ( value >= 1000 ) {
+ return `${ ( value / 1000 ).toFixed( 1 ) }K`;
+ }
+ return value.toString();
+};
+
+// Custom No Data Component
+const CustomNoDataComponent = () => (
+
+
+
No chart data available
+
+ Please select a different time period or check your filters
+
+
+);
+
type Story = StoryObj;
export const LineChartSimple: Story = {
@@ -59,10 +109,13 @@ export const LineChartSimple: Story = {
showYAxis: false,
showTooltip: true,
showCartesianGrid: true,
- tickFormatter: monthFormatter,
+ xAxisTickFormatter: monthFormatter,
xAxisDataKey: 'month',
xAxisFontSize: 'sm',
withDots: false,
+ lineChartWrapperProps: {
+ margin: { top: 5, right: 15, bottom: 5, left: 15 },
+ },
},
};
@@ -75,10 +128,13 @@ export const LineChartWithDots: Story = {
showYAxis: false,
showTooltip: true,
showCartesianGrid: true,
- tickFormatter: monthFormatter,
+ xAxisTickFormatter: monthFormatter,
xAxisDataKey: 'month',
xAxisFontSize: 'sm',
withDots: true,
+ lineChartWrapperProps: {
+ margin: { top: 5, right: 15, bottom: 5, left: 15 },
+ },
},
};
@@ -91,10 +147,13 @@ export const LineChartMultiple: Story = {
showYAxis: false,
showTooltip: true,
showCartesianGrid: true,
- tickFormatter: monthFormatter,
+ xAxisTickFormatter: monthFormatter,
xAxisDataKey: 'month',
xAxisFontSize: 'sm',
withDots: false,
+ lineChartWrapperProps: {
+ margin: { top: 5, right: 15, bottom: 5, left: 15 },
+ },
},
};
@@ -107,7 +166,7 @@ export const BiaxialLineChart: Story = {
showYAxis: true,
showTooltip: true,
showCartesianGrid: true,
- tickFormatter: monthFormatter,
+ xAxisTickFormatter: monthFormatter,
xAxisDataKey: 'month',
xAxisFontSize: 'sm',
withDots: true,
@@ -115,7 +174,68 @@ export const BiaxialLineChart: Story = {
chartWidth: 500,
chartHeight: 300,
lineChartWrapperProps: {
- margin: { top: 5, right: 5, bottom: 5, left: 5 },
+ margin: { top: 5, right: 45, bottom: 5, left: 5 },
+ },
+ yAxisFontColor: [ '#3b82f6', '#10B981' ],
+ },
+};
+
+export const LineChartWithFormattedYAxis: Story = {
+ args: {
+ data: largeValuesData,
+ dataKeys: largeDataKeys,
+ colors: [ { stroke: '#3b82f6' }, { stroke: '#f97316' } ],
+ showXAxis: true,
+ showYAxis: true,
+ showTooltip: true,
+ showCartesianGrid: true,
+ xAxisTickFormatter: monthFormatter,
+ yAxisTickFormatter: yAxisFormatter,
+ xAxisDataKey: 'month',
+ xAxisFontSize: 'sm',
+ withDots: true,
+ chartWidth: 500,
+ chartHeight: 300,
+ lineChartWrapperProps: {
+ margin: { top: 5, right: 15, bottom: 5, left: 35 },
},
},
};
+
+export const BiaxialLineChartWithFormattedYAxis: Story = {
+ args: {
+ data: largeValuesData,
+ dataKeys: largeDataKeys,
+ colors: [ { stroke: '#2563EB' }, { stroke: '#10B981' } ],
+ showXAxis: true,
+ showYAxis: true,
+ showTooltip: true,
+ showCartesianGrid: true,
+ xAxisTickFormatter: monthFormatter,
+ yAxisTickFormatter: yAxisFormatter,
+ xAxisDataKey: 'month',
+ xAxisFontSize: 'sm',
+ withDots: true,
+ biaxial: true,
+ chartWidth: 500,
+ chartHeight: 300,
+ lineChartWrapperProps: {
+ margin: { top: 5, right: 45, bottom: 5, left: 35 },
+ },
+ yAxisFontColor: [ '#3b82f6', '#10B981' ],
+ },
+};
+
+export const LineChartWithCustomNoDataComponent: Story = {
+ args: {
+ data: emptyData,
+ dataKeys: [ 'desktop' ],
+ colors: [ { stroke: '#3b82f6' } ],
+ showXAxis: true,
+ showYAxis: true,
+ xAxisDataKey: 'month',
+ chartWidth: 500,
+ chartHeight: 300,
+ noDataComponent: ,
+ },
+};
diff --git a/src/components/line-chart/line-chart.tsx b/src/components/line-chart/line-chart.tsx
index ba160144..cd5f634c 100644
--- a/src/components/line-chart/line-chart.tsx
+++ b/src/components/line-chart/line-chart.tsx
@@ -10,6 +10,12 @@ import {
import ChartTooltipContent from './chart-tooltip-content';
import Label from '../label';
import type { CategoricalChartProps } from 'recharts/types/chart/generateCategoricalChart';
+import { type ReactNode } from 'react';
+
+// Default color constants
+const DEFAULT_FONT_COLOR = '#6B7280';
+const DEFAULT_GRID_COLOR = '#E5E7EB';
+const DEFAULT_LINE_COLORS = [ { stroke: '#2563EB' }, { stroke: '#38BDF8' } ];
interface DataItem {
[key: string]: number | string;
@@ -47,8 +53,17 @@ interface LineChartProps {
showCartesianGrid?: boolean;
/** A function used to format the ticks on the x-axis, e.g., for formatting dates or numbers. */
+ xAxisTickFormatter?: ( value: string ) => string;
+
+ /**
+ * A function used to format the ticks on the x-axis, e.g., for formatting dates or numbers.
+ * @deprecated Use `xAxisTickFormatter` instead.
+ */
tickFormatter?: ( value: string ) => string;
+ /** A function used to format the ticks on the y-axis, e.g., for converting 1000 to 1K. */
+ yAxisTickFormatter?: ( value: number ) => string;
+
/** The key in the data objects representing values for the x-axis. */
xAxisDataKey?: string;
@@ -61,8 +76,12 @@ interface LineChartProps {
/** Font color for the labels on the x-axis. */
xAxisFontColor?: string;
- /** Font color for the labels on the y-axis. */
- yAxisFontColor?: string;
+ /**
+ * Font color for the labels on the y-axis.
+ * When biaxial is true, you can provide an array of two colors [leftAxisColor, rightAxisColor].
+ * If a single color is provided, it will be used for both axes.
+ */
+ yAxisFontColor?: string | string[];
/** Width of the chart container. */
chartWidth?: number | string;
@@ -98,6 +117,12 @@ interface LineChartProps {
* Biaxial chart.
*/
biaxial?: boolean;
+
+ /**
+ * Custom component to display when no data is available.
+ * If not provided, a default "No data available" message will be displayed.
+ */
+ noDataComponent?: ReactNode;
}
const LineChart = ( {
@@ -110,23 +135,24 @@ const LineChart = ( {
tooltipIndicator = 'dot', // dot, line, dashed
tooltipLabelKey,
showCartesianGrid = true,
+ xAxisTickFormatter,
+ yAxisTickFormatter,
tickFormatter,
xAxisDataKey,
yAxisDataKey,
xAxisFontSize = 'sm', // sm, md, lg
- xAxisFontColor = '#6B7280',
- yAxisFontColor = '#6B7280',
+ xAxisFontColor = DEFAULT_FONT_COLOR,
+ yAxisFontColor = DEFAULT_FONT_COLOR,
chartWidth = 350,
chartHeight = 200,
withDots = false,
lineChartWrapperProps,
strokeDasharray = '3 3',
- gridColor = '#E5E7EB',
+ gridColor = DEFAULT_GRID_COLOR,
biaxial = false,
+ noDataComponent,
}: LineChartProps ) => {
- const defaultColors = [ { stroke: '#2563EB' }, { stroke: '#38BDF8' } ];
-
- const appliedColors = colors.length > 0 ? colors : defaultColors;
+ const appliedColors = colors.length > 0 ? colors : DEFAULT_LINE_COLORS;
const fontSizeMap = {
sm: '12px',
@@ -136,11 +162,23 @@ const LineChart = ( {
const fontSizeVariant = fontSizeMap[ xAxisFontSize ] || fontSizeMap.sm;
+ // Handle Y-axis colors for biaxial chart
+ const getYAxisFontColor = ( index = 0 ) => {
+ if ( Array.isArray( yAxisFontColor ) ) {
+ return (
+ yAxisFontColor[ index ] || yAxisFontColor[ 0 ] || DEFAULT_FONT_COLOR
+ );
+ }
+ return yAxisFontColor;
+ };
+
if ( ! data || data.length === 0 ) {
return (
-
+ noDataComponent || (
+
+ )
);
}
@@ -159,7 +197,7 @@ const LineChart = ( {
tickLine={ false }
axisLine={ false }
tickMargin={ 8 }
- tickFormatter={ tickFormatter }
+ tickFormatter={ xAxisTickFormatter || tickFormatter }
tick={ {
fontSize: fontSizeVariant,
fill: xAxisFontColor,
@@ -173,9 +211,10 @@ const LineChart = ( {
tickLine={ false }
axisLine={ false }
tickMargin={ 8 }
+ tickFormatter={ yAxisTickFormatter }
tick={ {
fontSize: fontSizeVariant,
- fill: yAxisFontColor,
+ fill: getYAxisFontColor( 0 ),
} }
hide={ ! showYAxis }
orientation="left"
@@ -188,9 +227,10 @@ const LineChart = ( {
tickLine={ false }
axisLine={ false }
tickMargin={ 8 }
+ tickFormatter={ yAxisTickFormatter }
tick={ {
fontSize: fontSizeVariant,
- fill: yAxisFontColor,
+ fill: getYAxisFontColor( 1 ),
} }
orientation="right"
hide={ ! showYAxis }
diff --git a/src/components/text/text.stories.tsx b/src/components/text/text.stories.tsx
index 32138d79..0f4738d8 100644
--- a/src/components/text/text.stories.tsx
+++ b/src/components/text/text.stories.tsx
@@ -52,7 +52,8 @@ export default {
'h6',
'div',
],
- description: 'The element to render the text as. Any HTML element or React component can be added here.',
+ description:
+ 'The element to render the text as. Any HTML element or React component can be added here.',
},
children: {
control: 'text',