diff --git a/README.md b/README.md
index 1ec364cd..9d8f2e29 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,7 @@ Using Force UI as a dependency in package.json -
```json
"dependencies": {
- "@bsf/force-ui": "git+https://github.com/brainstormforce/force-ui#1.6.0"
+ "@bsf/force-ui": "git+https://github.com/brainstormforce/force-ui#1.6.1"
}
```
@@ -28,7 +28,7 @@ npm install
Or you can directly run the following command to install the package -
```bash
-npm i -S @bsf/force-ui@git+https://github.com/brainstormforce/force-ui.git#1.6.0
+npm i -S @bsf/force-ui@git+https://github.com/brainstormforce/force-ui.git#1.6.1
```
diff --git a/changelog.txt b/changelog.txt
index 744e805f..b9259052 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,3 +1,9 @@
+Version 1.6.1 - 11th April, 2025
+- Improvement - Added a new prop to the LineChart component to enable Biaxial Line chart functionality, along with various UI enhancements for improved user experience.
+- Improvement - Added customizable properties for the LineChart and AreaChart components to tailor x-axis and y-axis ticks and labels for better data visualization.
+- Improvement - Introduced a `className` prop in the Dropzone component to enhance customizability and allow for more flexible styling options.
+- Fix - Corrected the positioning of days in the DatePicker component to ensure accurate display and improved user experience.
+
Version 1.6.0 - 8th April, 2025
- New - Introduced a versatile Text component that supports multiple HTML elements and customizable styles for enhanced typography flexibility.
- Improvement - Display xAxis data on the tooltip when hovering.
diff --git a/package-lock.json b/package-lock.json
index bfc0a1f9..ff173138 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@bsf/force-ui",
- "version": "1.6.0",
+ "version": "1.6.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@bsf/force-ui",
- "version": "1.6.0",
+ "version": "1.6.1",
"license": "ISC",
"dependencies": {
"@emotion/is-prop-valid": "^1.3.0",
diff --git a/package.json b/package.json
index 48870db4..642a6425 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@bsf/force-ui",
- "version": "1.6.0",
+ "version": "1.6.1",
"description": "Library of components for the BSF project",
"main": "./dist/force-ui.cjs.js",
"module": "./dist/force-ui.es.js",
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 fe9f1c13..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,18 +203,20 @@ const AreaChart = ( {
tickLine={ false }
axisLine={ false }
tickMargin={ 8 }
- tickFormatter={ tickFormatter }
+ tickFormatter={ xAxisTickFormatter || tickFormatter }
tick={ {
fontSize: fontSizeVariant,
fill: xAxisFontColor,
} }
hide={ ! showXAxis }
+ interval="preserveStartEnd"
/>
) }
-
+
{ item[ nameKey ] || item.dataKey }
{ formatter
diff --git a/src/components/datepicker/datepicker-component.tsx b/src/components/datepicker/datepicker-component.tsx
index 58319a9a..83fcc9ba 100644
--- a/src/components/datepicker/datepicker-component.tsx
+++ b/src/components/datepicker/datepicker-component.tsx
@@ -349,7 +349,10 @@ const DatePickerComponent = ( {
const shouldShowDay =
isThisMonth || isRangeEndInCurrentMonth || isPartOfRange;
- const showOutsideDates = ! showOutsideDays && isOutside;
+
+ // Fix: Corrected the logic for hiding outside dates
+ // Only hide outside days when showOutsideDays is false AND the day is outside
+ const hideOutsideDay = ! showOutsideDays && isOutside;
// Common class for disabled outside days
const disabledOutsideClass =
@@ -398,7 +401,7 @@ const DatePickerComponent = ( {
className={ cn(
buttonClasses,
isToday && 'font-semibold',
- showOutsideDates && 'opacity-0',
+ hideOutsideDay && 'opacity-0',
isRangeStart && 'fui-range-start',
isRangeEnd && 'fui-range-end',
isRangeMiddle && 'fui-range-middle',
@@ -415,8 +418,7 @@ const DatePickerComponent = ( {
data-selected={ isSelected }
data-day={ format( day.date, 'yyyy-MM-dd' ) }
>
- { ( ! showOutsideDates || ( isPartOfRange && shouldShowDay ) ) &&
- customDayProps.children }
+ { customDayProps.children }
{ isToday && shouldShowDay && (
) }
@@ -553,6 +555,7 @@ const DatePickerComponent = ( {
...classNames,
} }
numberOfMonths={ numberOfMonths }
+ showOutsideDays={ true }
components={ {
MonthCaption:
CustomMonthCaption as unknown as CustomComponents['MonthCaption'],
diff --git a/src/components/dropzone/dropzone.tsx b/src/components/dropzone/dropzone.tsx
index a4f8881d..09581dc7 100644
--- a/src/components/dropzone/dropzone.tsx
+++ b/src/components/dropzone/dropzone.tsx
@@ -21,6 +21,10 @@ export interface DropzoneProps {
error?: boolean;
/** Error text to display */
errorText?: string;
+ /** Custom class name for the dropzone */
+ className?: string;
+ /** Custom class name for the wrapper */
+ wrapperClassName?: string;
}
// Context interface for file data sharing
@@ -127,6 +131,8 @@ export const Dropzone = ( {
disabled = false,
error = false,
errorText = 'Upload failed, please try again.',
+ className = '',
+ wrapperClassName = '',
}: DropzoneProps ) => {
const [ isLoading, setIsLoading ] = useState( false );
const [ file, setFile ] = useState( null );
@@ -214,7 +220,7 @@ export const Dropzone = ( {
-
+