import { scaleBand } from '@visx/scale'; import { dec, equals, gt, pick } from 'ramda'; import { memo, type ReactElement } from 'react'; import Bar from './Bar'; import type { BarStyle } from './models'; import { type UseBarStackProps, useBarStack } from './useBarStack'; const xScale = scaleBand({ domain: [0, 0], padding: 0, range: [0, 0] }); interface Props extends Omit { barIndex: number; barPadding: number; barStyle: BarStyle; barWidth: number; isTooltipHidden: boolean; neutralValue: number; isStacked?: boolean; } interface GetPaddingProps { padding: number; size: number; isNegativeValue: boolean; } const getPadding = ({ padding, size, isNegativeValue }: GetPaddingProps): number => { if (!isNegativeValue) { return padding; } return padding + size; }; const BarStack = ({ timeSeries, isHorizontal, yScale, lines, barWidth, barPadding, barIndex, isTooltipHidden, barStyle = { opacity: 1, radius: 0.2 }, neutralValue, isStacked }: Props): ReactElement => { const { BarStackComponent, commonBarStackProps, colorScale, lineKeys, exitBar, hoverBar } = useBarStack({ isHorizontal, lines, timeSeries, xScale, yScale }); return ( {/* biome-ignore lint/suspicious/noExplicitAny: visx BarStack union */} {(barStacks: Array) => { // biome-ignore lint/suspicious/noExplicitAny: visx BarStack union return barStacks.map((barStack: any, index: number) => // biome-ignore lint/suspicious/noExplicitAny: visx BarStack union barStack.bars.map((bar: any) => { const shouldApplyRadiusOnBottom = equals(index, 0); const shouldApplyRadiusOnTop = equals(index, dec(barStacks.length)); const isNegativeValue = gt(0, bar.bar[1]); const shouldRetrievePadding = isNegativeValue && isStacked && !shouldApplyRadiusOnBottom; const barRoundedProps = { [isHorizontal ? 'bottom' : 'left']: shouldApplyRadiusOnBottom, [isHorizontal ? 'top' : 'right']: shouldApplyRadiusOnTop }; const barY = shouldRetrievePadding ? getPadding({ isNegativeValue, padding: bar.y, size: bar.height }) : bar.y; return ( ); }) ); }} ); }; const propsToMemoize = [ 'timeSeries', 'isHorizontal', 'barWidth', 'lines', 'barPadding', 'barIndex', 'isTooltipHidden', 'barStyle', 'neutralValue' ]; export default memo(BarStack, (prevProps, nextProps) => { const prevYScaleDomain = prevProps.yScale.domain(); const prevYScaleRange = prevProps.yScale.range(); const nextYScaleDomain = nextProps.yScale.domain(); const nextYScaleRange = nextProps.yScale.range(); return ( equals( [...prevYScaleDomain, ...prevYScaleRange], [...nextYScaleDomain, ...nextYScaleRange] ) && // @ts-expect-error - suppressing pre-existing type mismatch equals(pick(propsToMemoize, prevProps), pick(propsToMemoize, nextProps)) ); });