From bac0d0b9d470fb53ab5bb6fcf93dd37edfd4289b Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia Date: Thu, 27 Mar 2025 15:45:57 +0530 Subject: [PATCH] chore: code refactor --- packages/constants/src/chart.ts | 2 +- .../propel/src/charts/area-chart/root.tsx | 175 ++++++++++++------ packages/propel/src/charts/bar-chart/bar.tsx | 49 +++-- packages/propel/src/charts/bar-chart/root.tsx | 116 ++++++++---- .../propel/src/charts/components/legend.tsx | 77 ++++++++ .../src/charts/{ => components}/tick.tsx | 2 +- .../propel/src/charts/components/tooltip.tsx | 60 ++++++ .../propel/src/charts/line-chart/root.tsx | 141 +++++++++----- .../src/charts/pie-chart/active-shape.tsx | 31 ++++ packages/propel/src/charts/pie-chart/root.tsx | 130 +++++++++++-- .../propel/src/charts/pie-chart/tooltip.tsx | 25 ++- packages/propel/src/charts/tooltip.tsx | 41 ---- packages/propel/src/charts/tree-map/root.tsx | 3 + packages/types/src/charts.d.ts | 73 ++++++-- 14 files changed, 688 insertions(+), 237 deletions(-) create mode 100644 packages/propel/src/charts/components/legend.tsx rename packages/propel/src/charts/{ => components}/tick.tsx (90%) create mode 100644 packages/propel/src/charts/components/tooltip.tsx create mode 100644 packages/propel/src/charts/pie-chart/active-shape.tsx delete mode 100644 packages/propel/src/charts/tooltip.tsx diff --git a/packages/constants/src/chart.ts b/packages/constants/src/chart.ts index f921b8b372b..bddd0fd3835 100644 --- a/packages/constants/src/chart.ts +++ b/packages/constants/src/chart.ts @@ -1,2 +1,2 @@ export const LABEL_CLASSNAME = "uppercase text-custom-text-300/60 text-sm tracking-wide"; -export const AXIS_LINE_CLASSNAME = "text-custom-text-400/70"; +export const AXIS_LABEL_CLASSNAME = "uppercase text-custom-text-300/60 text-sm tracking-wide"; diff --git a/packages/propel/src/charts/area-chart/root.tsx b/packages/propel/src/charts/area-chart/root.tsx index 710c5f70d6a..7d4e9e6ba97 100644 --- a/packages/propel/src/charts/area-chart/root.tsx +++ b/packages/propel/src/charts/area-chart/root.tsx @@ -1,14 +1,14 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ "use client"; -import React, { useMemo } from "react"; -import { AreaChart as CoreAreaChart, Area, ResponsiveContainer, Tooltip, XAxis, YAxis } from "recharts"; +import React, { useMemo, useState } from "react"; +import { Area, Legend, ResponsiveContainer, Tooltip, XAxis, YAxis, Line, ComposedChart, CartesianGrid } from "recharts"; // plane imports -import { AXIS_LINE_CLASSNAME, LABEL_CLASSNAME } from "@plane/constants"; +import { AXIS_LABEL_CLASSNAME } from "@plane/constants"; import { TAreaChartProps } from "@plane/types"; // local components -import { CustomXAxisTick, CustomYAxisTick } from "../tick"; -import { CustomTooltip } from "../tooltip"; +import { getLegendProps } from "../components/legend"; +import { CustomXAxisTick, CustomYAxisTick } from "../components/tick"; +import { CustomTooltip } from "../components/tooltip"; export const AreaChart = React.memo((props: TAreaChartProps) => { const { @@ -16,107 +16,174 @@ export const AreaChart = React.memo((props: areas, xAxis, yAxis, - className = "w-full h-96", + className, + legend, + margin, tickCount = { x: undefined, y: 10, }, showTooltip = true, + comparisonLine, } = props; + // states + const [activeArea, setActiveArea] = useState(null); + const [activeLegend, setActiveLegend] = useState(null); // derived values const itemKeys = useMemo(() => areas.map((area) => area.key), [areas]); - const itemDotClassNames = useMemo( - () => areas.reduce((acc, area) => ({ ...acc, [area.key]: area.dotClassName }), {}), + const itemLabels: Record = useMemo( + () => areas.reduce((acc, area) => ({ ...acc, [area.key]: area.label }), {}), [areas] ); + const itemDotColors = useMemo(() => areas.reduce((acc, area) => ({ ...acc, [area.key]: area.fill }), {}), [areas]); const renderAreas = useMemo( () => areas.map((area) => ( setActiveArea(area.key)} + onMouseLeave={() => setActiveArea(null)} + className="[&_path]:transition-opacity [&_path]:duration-200" /> )), - [areas] + [activeLegend, areas] ); + // create comparison line data for straight line from origin to last point + const comparisonLineData = useMemo(() => { + if (!data || data.length === 0) return []; + // get the last data point + const lastPoint = data[data.length - 1]; + // for the y-value in the last point, use its yAxis key value + const lastYValue = lastPoint[yAxis.key] || 0; + // create data for a straight line that has points at each x-axis position + return data.map((item, index) => { + // calculate the y value for this point on the straight line + // using linear interpolation between (0,0) and (last_x, last_y) + const ratio = index / (data.length - 1); + const interpolatedValue = ratio * lastYValue; + + return { + [xAxis.key]: item[xAxis.key], + comparisonLine: interpolatedValue, + }; + }); + }, [data, xAxis.key]); + return (
- + } - tickLine={{ - stroke: "currentColor", - className: AXIS_LINE_CLASSNAME, - }} - axisLine={{ - stroke: "currentColor", - className: AXIS_LINE_CLASSNAME, - }} - label={{ - value: xAxis.label, - dy: 28, - className: LABEL_CLASSNAME, - }} + tickLine={false} + axisLine={false} + label={ + xAxis.label && { + value: xAxis.label, + dy: 28, + className: AXIS_LABEL_CLASSNAME, + } + } tickCount={tickCount.x} /> } tickCount={tickCount.y} allowDecimals={!!yAxis.allowDecimals} /> + {legend && ( + // @ts-expect-error recharts types are not up to date + itemLabels[value]} + onMouseEnter={(payload) => setActiveLegend(payload.value)} + onMouseLeave={() => setActiveLegend(null)} + {...getLegendProps(legend)} + /> + )} {showTooltip && ( ( )} /> )} {renderAreas} - + {comparisonLine && ( + + )} +
); diff --git a/packages/propel/src/charts/bar-chart/bar.tsx b/packages/propel/src/charts/bar-chart/bar.tsx index 339be704ddb..5cc9dac2fde 100644 --- a/packages/propel/src/charts/bar-chart/bar.tsx +++ b/packages/propel/src/charts/bar-chart/bar.tsx @@ -15,10 +15,25 @@ const calculatePercentage = ( }; const MIN_BAR_HEIGHT_FOR_INTERNAL_TEXT = 14; // Minimum height needed to show text inside -const BAR_BORDER_RADIUS = 2; // Border radius for each bar +const BAR_TOP_BORDER_RADIUS = 4; // Border radius for each bar +const BAR_BOTTOM_BORDER_RADIUS = 4; // Border radius for each bar export const CustomBar = React.memo((props: any) => { - const { fill, x, y, width, height, dataKey, stackKeys, payload, textClassName, showPercentage } = props; + const { + opacity, + fill, + x, + y, + width, + height, + dataKey, + stackKeys, + payload, + textClassName, + showPercentage, + showTopBorderRadius, + showBottomBorderRadius, + } = props; // Calculate text position const TEXT_PADDING_Y = Math.min(6, Math.abs(MIN_BAR_HEIGHT_FOR_INTERNAL_TEXT - height / 2)); const textY = y + height - TEXT_PADDING_Y; // Position inside bar if tall enough @@ -34,24 +49,28 @@ export const CustomBar = React.memo((props: any) => { // bar percentage is a number !Number.isNaN(currentBarPercentage); + const topBorderRadius = showTopBorderRadius ? BAR_TOP_BORDER_RADIUS : 0; + const bottomBorderRadius = showBottomBorderRadius ? BAR_BOTTOM_BORDER_RADIUS : 0; + if (!height) return null; + return ( {showText && ( (props: TBarChartProps) => { @@ -18,19 +28,25 @@ export const BarChart = React.memo((props: T xAxis, yAxis, barSize = 40, - className = "w-full h-96", + className, + legend, + margin, tickCount = { x: undefined, y: 10, }, showTooltip = true, } = props; + // states + const [activeBar, setActiveBar] = useState(null); + const [activeLegend, setActiveLegend] = useState(null); // derived values const stackKeys = useMemo(() => bars.map((bar) => bar.key), [bars]); - const stackDotClassNames = useMemo( - () => bars.reduce((acc, bar) => ({ ...acc, [bar.key]: bar.dotClassName }), {}), + const stackLabels: Record = useMemo( + () => bars.reduce((acc, bar) => ({ ...acc, [bar.key]: bar.label }), {}), [bars] ); + const stackDotColors = useMemo(() => bars.reduce((acc, bar) => ({ ...acc, [bar.key]: bar.fill }), {}), [bars]); const renderBars = useMemo( () => @@ -39,18 +55,29 @@ export const BarChart = React.memo((props: T key={bar.key} dataKey={bar.key} stackId={bar.stackId} - fill={bar.fillClassName} - shape={(shapeProps: any) => ( - - )} + opacity={!!activeLegend && activeLegend !== bar.key ? 0.1 : 1} + fill={bar.fill} + shape={(shapeProps: any) => { + const showTopBorderRadius = bar.showTopBorderRadius?.(shapeProps.dataKey, shapeProps.payload); + const showBottomBorderRadius = bar.showBottomBorderRadius?.(shapeProps.dataKey, shapeProps.payload); + + return ( + + ); + }} + className="[&_path]:transition-opacity [&_path]:duration-200" + onMouseEnter={() => setActiveBar(bar.key)} + onMouseLeave={() => setActiveBar(null)} /> )), - [stackKeys, bars] + [activeLegend, stackKeys, bars] ); return ( @@ -58,60 +85,71 @@ export const BarChart = React.memo((props: T + } - tickLine={{ - stroke: "currentColor", - className: AXIS_LINE_CLASSNAME, - }} - axisLine={{ - stroke: "currentColor", - className: AXIS_LINE_CLASSNAME, - }} + tickLine={false} + axisLine={false} label={{ value: xAxis.label, dy: 28, - className: LABEL_CLASSNAME, + className: AXIS_LABEL_CLASSNAME, }} tickCount={tickCount.x} /> } tickCount={tickCount.y} allowDecimals={!!yAxis.allowDecimals} /> + {legend && ( + // @ts-expect-error recharts types are not up to date + setActiveLegend(payload.value)} + onMouseLeave={() => setActiveLegend(null)} + formatter={(value) => stackLabels[value]} + {...getLegendProps(legend)} + /> + )} {showTooltip && ( ( )} /> diff --git a/packages/propel/src/charts/components/legend.tsx b/packages/propel/src/charts/components/legend.tsx new file mode 100644 index 00000000000..2be69c5cb55 --- /dev/null +++ b/packages/propel/src/charts/components/legend.tsx @@ -0,0 +1,77 @@ +import React from "react"; +import { LegendProps } from "recharts"; +// plane imports +import { TChartLegend } from "@plane/types"; +import { cn } from "@plane/utils"; + +export const getLegendProps = (args: TChartLegend): LegendProps => { + const { align, layout, verticalAlign } = args; + return { + layout, + align, + verticalAlign, + wrapperStyle: { + display: "flex", + overflow: "hidden", + ...(layout === "vertical" + ? { + top: 0, + alignItems: "center", + height: "100%", + } + : { + left: 0, + bottom: 0, + width: "100%", + justifyContent: "center", + }), + }, + content: , + }; +}; + +const CustomLegend = React.forwardRef< + HTMLDivElement, + React.ComponentProps<"div"> & + Pick & + TChartLegend +>((props, ref) => { + const { formatter, layout, onClick, onMouseEnter, onMouseLeave, payload } = props; + + if (!payload?.length) return null; + + return ( +
+ {payload.map((item, index) => ( +
onClick?.(item, index, e)} + onMouseEnter={(e) => onMouseEnter?.(item, index, e)} + onMouseLeave={(e) => onMouseLeave?.(item, index, e)} + > +
+ {/* @ts-expect-error recharts types are not up to date */} + {formatter?.(item.value, { value: item.value }, index) ?? item.payload?.name} +
+ ))} +
+ ); +}); +CustomLegend.displayName = "CustomLegend"; diff --git a/packages/propel/src/charts/tick.tsx b/packages/propel/src/charts/components/tick.tsx similarity index 90% rename from packages/propel/src/charts/tick.tsx rename to packages/propel/src/charts/components/tick.tsx index c631d7d6e2b..e26e25ef3d0 100644 --- a/packages/propel/src/charts/tick.tsx +++ b/packages/propel/src/charts/components/tick.tsx @@ -2,7 +2,7 @@ import React from "react"; // Common classnames -const AXIS_TICK_CLASSNAME = "fill-custom-text-400 text-sm capitalize"; +const AXIS_TICK_CLASSNAME = "fill-custom-text-300 text-sm"; export const CustomXAxisTick = React.memo(({ x, y, payload }: any) => ( diff --git a/packages/propel/src/charts/components/tooltip.tsx b/packages/propel/src/charts/components/tooltip.tsx new file mode 100644 index 00000000000..8931f7c718a --- /dev/null +++ b/packages/propel/src/charts/components/tooltip.tsx @@ -0,0 +1,60 @@ +import React from "react"; +import { NameType, Payload, ValueType } from "recharts/types/component/DefaultTooltipContent"; +// plane imports +import { Card, ECardSpacing } from "@plane/ui"; +import { cn } from "@plane/utils"; + +type Props = { + active: boolean | undefined; + activeKey?: string | null; + label: string | undefined; + payload: Payload[] | undefined; + itemKeys: string[]; + itemLabels: Record; + itemDotColors: Record; +}; + +export const CustomTooltip = React.memo((props: Props) => { + const { active, activeKey, label, payload, itemKeys, itemLabels, itemDotColors } = props; + // derived values + const filteredPayload = payload?.filter((item) => item.dataKey && itemKeys.includes(`${item.dataKey}`)); + + if (!active || !filteredPayload || !filteredPayload.length) return null; + + return ( + +

+ {label} +

+ {filteredPayload.map((item) => { + if (!item.dataKey) return null; + + return ( +
+
+ {itemDotColors[item?.dataKey] && ( +
+ )} + {itemLabels[item?.dataKey]}: +
+ {item?.value} +
+ ); + })} + + ); +}); +CustomTooltip.displayName = "CustomTooltip"; diff --git a/packages/propel/src/charts/line-chart/root.tsx b/packages/propel/src/charts/line-chart/root.tsx index c689fe9ba3c..6812797b792 100644 --- a/packages/propel/src/charts/line-chart/root.tsx +++ b/packages/propel/src/charts/line-chart/root.tsx @@ -1,107 +1,154 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ "use client"; -import React, { useMemo } from "react"; -import { LineChart as CoreLineChart, Line, ResponsiveContainer, Tooltip, XAxis, YAxis } from "recharts"; +import React, { useMemo, useState } from "react"; +import { + CartesianGrid, + LineChart as CoreLineChart, + Legend, + Line, + ResponsiveContainer, + Tooltip, + XAxis, + YAxis, +} from "recharts"; // plane imports -import { AXIS_LINE_CLASSNAME, LABEL_CLASSNAME } from "@plane/constants"; +import { AXIS_LABEL_CLASSNAME } from "@plane/constants"; import { TLineChartProps } from "@plane/types"; // local components -import { CustomXAxisTick, CustomYAxisTick } from "../tick"; -import { CustomTooltip } from "../tooltip"; +import { getLegendProps } from "../components/legend"; +import { CustomXAxisTick, CustomYAxisTick } from "../components/tick"; +import { CustomTooltip } from "../components/tooltip"; export const LineChart = React.memo((props: TLineChartProps) => { const { data, lines, + margin, xAxis, yAxis, - className = "w-full h-96", + className, tickCount = { x: undefined, y: 10, }, + legend, showTooltip = true, } = props; + // states + const [activeLine, setActiveLine] = useState(null); + const [activeLegend, setActiveLegend] = useState(null); // derived values const itemKeys = useMemo(() => lines.map((line) => line.key), [lines]); - const itemDotClassNames = useMemo( - () => lines.reduce((acc, line) => ({ ...acc, [line.key]: line.dotClassName }), {}), + const itemLabels: Record = useMemo( + () => lines.reduce((acc, line) => ({ ...acc, [line.key]: line.label }), {}), [lines] ); + const itemDotColors = useMemo(() => lines.reduce((acc, line) => ({ ...acc, [line.key]: line.stroke }), {}), [lines]); const renderLines = useMemo( () => lines.map((line) => ( - + setActiveLine(line.key)} + onMouseLeave={() => setActiveLine(null)} + /> )), - [lines] + [activeLegend, lines] ); return (
+ } - tickLine={{ - stroke: "currentColor", - className: AXIS_LINE_CLASSNAME, - }} - axisLine={{ - stroke: "currentColor", - className: AXIS_LINE_CLASSNAME, - }} - label={{ - value: xAxis.label, - dy: 28, - className: LABEL_CLASSNAME, - }} + tickLine={false} + axisLine={false} + label={ + xAxis.label && { + value: xAxis.label, + dy: 28, + className: AXIS_LABEL_CLASSNAME, + } + } tickCount={tickCount.x} /> } tickCount={tickCount.y} allowDecimals={!!yAxis.allowDecimals} /> + {legend && ( + // @ts-expect-error recharts types are not up to date + setActiveLegend(payload.value)} + onMouseLeave={() => setActiveLegend(null)} + formatter={(value) => itemLabels[value]} + {...getLegendProps(legend)} + /> + )} {showTooltip && ( ( )} /> diff --git a/packages/propel/src/charts/pie-chart/active-shape.tsx b/packages/propel/src/charts/pie-chart/active-shape.tsx new file mode 100644 index 00000000000..61c14e28116 --- /dev/null +++ b/packages/propel/src/charts/pie-chart/active-shape.tsx @@ -0,0 +1,31 @@ +import React from "react"; +import { Sector } from "recharts"; + +export const CustomActiveShape = React.memo((props: any) => { + const { cx, cy, cornerRadius, innerRadius, outerRadius, startAngle, endAngle, fill } = props; + + return ( + + + + + ); +}); diff --git a/packages/propel/src/charts/pie-chart/root.tsx b/packages/propel/src/charts/pie-chart/root.tsx index d9e2558ed0f..1110260b9d5 100644 --- a/packages/propel/src/charts/pie-chart/root.tsx +++ b/packages/propel/src/charts/pie-chart/root.tsx @@ -1,45 +1,145 @@ "use client"; -import React, { useMemo } from "react"; -import { Cell, PieChart as CorePieChart, Pie, ResponsiveContainer, Tooltip } from "recharts"; +import React, { useMemo, useState } from "react"; +import { Cell, PieChart as CorePieChart, Label, Legend, Pie, ResponsiveContainer, Tooltip } from "recharts"; // plane imports import { TPieChartProps } from "@plane/types"; // local components +import { getLegendProps } from "../components/legend"; +import { CustomActiveShape } from "./active-shape"; import { CustomPieChartTooltip } from "./tooltip"; export const PieChart = React.memo((props: TPieChartProps) => { - const { data, dataKey, cells, className = "w-full h-96", innerRadius, outerRadius, showTooltip = true } = props; + const { + data, + dataKey, + cells, + className, + innerRadius, + legend, + margin, + outerRadius, + showTooltip = true, + showLabel, + customLabel, + centerLabel, + cornerRadius, + paddingAngle, + tooltipLabel, + } = props; + // states + const [activeIndex, setActiveIndex] = useState(null); + const [activeLegend, setActiveLegend] = useState(null); const renderCells = useMemo( - () => cells.map((cell) => ), - [cells] + () => + cells.map((cell, index) => ( + setActiveIndex(index)} + onMouseLeave={() => setActiveIndex(null)} + /> + )), + [activeLegend, cells] ); return (
- + setActiveIndex(null)} + data={data} + dataKey={dataKey} + cx="50%" + cy="50%" + blendStroke + activeShape={} + innerRadius={innerRadius} + outerRadius={outerRadius} + cornerRadius={cornerRadius} + paddingAngle={paddingAngle} + labelLine={false} + label={ + showLabel + ? ({ payload, ...props }) => ( + + {customLabel?.(payload.count) ?? payload.count} + + ) + : undefined + } + > {renderCells} + {centerLabel && ( + + {legend && ( + // @ts-expect-error recharts types are not up to date + { + // @ts-expect-error recharts types are not up to date + const key: string | undefined = payload.payload?.key; + if (!key) return; + setActiveLegend(key); + setActiveIndex(null); + }} + onMouseLeave={() => setActiveLegend(null)} + {...getLegendProps(legend)} + /> + )} {showTooltip && ( { if (!active || !payload || !payload.length) return null; - const cellData = cells.find((c) => c.key === payload[0].name); + const cellData = cells.find((c) => c.key === payload[0].payload.key); if (!cellData) return null; - return ; + const label = tooltipLabel + ? typeof tooltipLabel === "function" + ? tooltipLabel(payload[0]?.payload?.payload) + : tooltipLabel + : dataKey; + return ; }} /> )} diff --git a/packages/propel/src/charts/pie-chart/tooltip.tsx b/packages/propel/src/charts/pie-chart/tooltip.tsx index 56c7fa34cdc..0a4a157de6a 100644 --- a/packages/propel/src/charts/pie-chart/tooltip.tsx +++ b/packages/propel/src/charts/pie-chart/tooltip.tsx @@ -2,27 +2,36 @@ import React from "react"; import { NameType, Payload, ValueType } from "recharts/types/component/DefaultTooltipContent"; // plane imports import { Card, ECardSpacing } from "@plane/ui"; -import { cn } from "@plane/utils"; type Props = { - dotClassName?: string; + dotColor?: string; label: string; payload: Payload[]; }; export const CustomPieChartTooltip = React.memo((props: Props) => { - const { dotClassName, label, payload } = props; + const { dotColor, label, payload } = props; return ( - -

+ +

{label}

{payload?.map((item) => (
-
- {item?.name}: - {item?.value} +
+
+ {item?.name}: +
+ {item?.value}
))} diff --git a/packages/propel/src/charts/tooltip.tsx b/packages/propel/src/charts/tooltip.tsx deleted file mode 100644 index e7f92a9cb1f..00000000000 --- a/packages/propel/src/charts/tooltip.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import React from "react"; -import { NameType, Payload, ValueType } from "recharts/types/component/DefaultTooltipContent"; -// plane imports -import { Card, ECardSpacing } from "@plane/ui"; -import { cn } from "@plane/utils"; - -type Props = { - active: boolean | undefined; - label: string | undefined; - payload: Payload[] | undefined; - itemKeys: string[]; - itemDotClassNames: Record; -}; - -export const CustomTooltip = React.memo((props: Props) => { - const { active, label, payload, itemKeys, itemDotClassNames } = props; - // derived values - const filteredPayload = payload?.filter((item) => item.dataKey && itemKeys.includes(`${item.dataKey}`)); - - if (!active || !filteredPayload || !filteredPayload.length) return null; - return ( - -

- {label} -

- {filteredPayload.map((item) => { - if (!item.dataKey) return null; - return ( -
- {itemDotClassNames[item?.dataKey] && ( -
- )} - {item?.name}: - {item?.value} -
- ); - })} - - ); -}); -CustomTooltip.displayName = "CustomTooltip"; diff --git a/packages/propel/src/charts/tree-map/root.tsx b/packages/propel/src/charts/tree-map/root.tsx index 47ea21d7275..7add4a6b6b7 100644 --- a/packages/propel/src/charts/tree-map/root.tsx +++ b/packages/propel/src/charts/tree-map/root.tsx @@ -31,6 +31,9 @@ export const TreeMapChart = React.memo((props: TreeMapChartProps) => { fill: "currentColor", className: "text-custom-background-90/80 cursor-pointer", }} + wrapperStyle={{ + pointerEvents: "auto", + }} /> )} diff --git a/packages/types/src/charts.d.ts b/packages/types/src/charts.d.ts index 473c1077e89..184b2b5d96c 100644 --- a/packages/types/src/charts.d.ts +++ b/packages/types/src/charts.d.ts @@ -1,3 +1,16 @@ +export type TChartLegend = { + align: "left" | "center" | "right"; + verticalAlign: "top" | "middle" | "bottom"; + layout: "horizontal" | "vertical"; +}; + +export type TChartMargin = { + top?: number; + right?: number; + bottom?: number; + left?: number; +}; + export type TChartData = { // required key [key in K]: string | number; @@ -7,15 +20,19 @@ type TChartProps = { data: TChartData[]; xAxis: { key: keyof TChartData; - label: string; + label?: string; + strokeColor?: string; }; yAxis: { - key: keyof TChartData; - label: string; - domain?: [number, number]; allowDecimals?: boolean; + domain?: [number, number]; + key: keyof TChartData; + label?: string; + strokeColor?: string; }; className?: string; + legend?: TChartLegend; + margin?: TChartMargin; tickCount?: { x?: number; y?: number; @@ -25,11 +42,13 @@ type TChartProps = { export type TBarItem = { key: T; - fillClassName: string; + label: string; + fill: string; textClassName: string; - dotClassName?: string; showPercentage?: boolean; stackId: string; + showTopBorderRadius?: (barKey: string, payload: any) => boolean; + showBottomBorderRadius?: (barKey: string, payload: any) => boolean; }; export type TBarChartProps = TChartProps & { @@ -39,9 +58,13 @@ export type TBarChartProps = TChartProps = { key: T; - className?: string; + label: string; + dashedLine: boolean; + fill: string; + showDot: boolean; + smoothCurves: boolean; + stroke: string; style?: Record; - dotClassName?: string; }; export type TLineChartProps = TChartProps & { @@ -50,31 +73,49 @@ export type TLineChartProps = TChartProps = { key: T; + label: string; stackId: string; - className?: string; + fill: string; + fillOpacity: number; + showDot: boolean; + smoothCurves: boolean; + strokeColor: string; + strokeOpacity: number; style?: Record; - dotClassName?: string; }; export type TAreaChartProps = TChartProps & { areas: TAreaItem[]; + comparisonLine?: { + dashedLine: boolean; + strokeColor: string; + }; }; export type TCellItem = { key: T; - className?: string; - style?: Record; - dotClassName?: string; + fill: string; }; export type TPieChartProps = Pick< TChartProps, - "className" | "data" | "showTooltip" + "className" | "data" | "showTooltip" | "legend" | "margin" > & { dataKey: T; cells: TCellItem[]; - innerRadius?: number; - outerRadius?: number; + innerRadius?: number | string; + outerRadius?: number | string; + cornerRadius?: number; + paddingAngle?: number; + showLabel: boolean; + customLabel?: (value: any) => string; + centerLabel?: { + className?: string; + fill: string; + style?: React.CSSProperties; + text?: string | number; + }; + tooltipLabel?: string | ((payload: any) => string); }; export type TreeMapItem = {