import { defaults, isEmpty } from "lodash";
import React from "react";
import {
Background,
Helpers,
Hooks,
UserProps,
VictoryContainer,
VictoryTheme,
Wrapper,
CategoryPropType,
DomainPropType,
EventPropTypeInterface,
StringOrNumberOrCallback,
VictoryCommonProps,
VictoryStyleInterface,
VictoryStyleObject,
} from "victory-core";
import { VictorySharedEvents } from "victory-shared-events";
import { VictoryAxis } from "victory-axis";
import { VictoryPolarAxis } from "victory-polar-axis";
import {
getBackgroundWithProps,
getChildComponents,
getCalculatedProps,
getChildren,
} from "./helper-methods";
import isEqual from "react-fast-compare";
const fallbackProps = {
width: 450,
height: 300,
padding: 50,
};
const defaultProps = {
backgroundComponent: ,
containerComponent: ,
defaultAxes: {
independent: ,
dependent: ,
},
defaultPolarAxes: {
independent: ,
dependent: ,
},
groupComponent: ,
standalone: true,
theme: VictoryTheme.grayscale,
};
const VictoryChartImpl: React.FC = (initialProps) => {
const propsWithDefaults = React.useMemo(
() => defaults({}, initialProps, defaultProps),
[initialProps],
);
const role = "chart";
const { getAnimationProps, setAnimationState, getProps } =
Hooks.useAnimationState();
const props = getProps(propsWithDefaults);
const modifiedProps = Helpers.modifyProps(props, fallbackProps, role);
const {
desc,
eventKey,
containerComponent,
standalone,
groupComponent,
externalEventMutations,
width,
height,
theme,
polar,
name,
title,
} = modifiedProps;
const axes = props.polar
? modifiedProps.defaultPolarAxes
: modifiedProps.defaultAxes;
const childComponents = React.useMemo(
() => getChildComponents(modifiedProps, axes),
[modifiedProps, axes],
);
const calculatedProps = React.useMemo(
() => getCalculatedProps(modifiedProps, childComponents),
[modifiedProps, childComponents],
);
const { domain, scale, style, origin, horizontal } = calculatedProps;
const newChildren = React.useMemo(() => {
const children = getChildren(props, childComponents, calculatedProps);
const mappedChildren = children.map((child, index) => {
const childProps = Object.assign(
{ animate: getAnimationProps(props, child, index) },
child.props,
);
return React.cloneElement(child, childProps);
});
if (props.style && props.style.background) {
const backgroundComponent = getBackgroundWithProps(
props,
calculatedProps,
);
mappedChildren.unshift(backgroundComponent);
}
return mappedChildren;
}, [getAnimationProps, childComponents, props, calculatedProps]);
const containerProps = React.useMemo(() => {
if (standalone) {
return {
desc,
domain,
width,
height,
horizontal,
name,
origin: polar ? origin : undefined,
polar,
theme,
title,
scale,
standalone,
style: style.parent,
};
}
return {};
}, [
desc,
domain,
height,
horizontal,
name,
origin,
polar,
scale,
standalone,
style,
title,
theme,
width,
]);
const container = React.useMemo(() => {
if (standalone) {
const defaultContainerProps = defaults(
{},
containerComponent.props,
containerProps,
UserProps.getSafeUserProps(propsWithDefaults),
);
return React.cloneElement(containerComponent, defaultContainerProps);
}
return groupComponent;
}, [
groupComponent,
standalone,
containerComponent,
containerProps,
propsWithDefaults,
]);
const events = React.useMemo(() => {
return Wrapper.getAllEvents(props);
}, [props]);
const previousProps = Hooks.usePreviousProps(propsWithDefaults);
React.useEffect(() => {
// This is called before dismount to keep state in sync
return () => {
if (propsWithDefaults.animate) {
setAnimationState(previousProps, propsWithDefaults);
}
};
}, [setAnimationState, previousProps, propsWithDefaults]);
if (!isEmpty(events)) {
return (
{newChildren}
);
}
return React.cloneElement(container, container.props, newChildren);
};
export const VictoryChart = React.memo(VictoryChartImpl, isEqual);
VictoryChart.displayName = "VictoryChart";
// @ts-expect-error FIXME: Does this "expectedComponents" do anything?
VictoryChart.expectedComponents = ["groupComponent", "containerComponent"];
export type AxesType = {
dependent?: React.ReactElement | null;
independent?: React.ReactElement | null;
};
export interface VictoryChartProps extends VictoryCommonProps {
backgroundComponent?: React.ReactElement;
categories?: CategoryPropType;
children?: React.ReactNode | React.ReactNode[];
desc?: string;
defaultAxes?: AxesType;
defaultPolarAxes?: AxesType;
domain?: DomainPropType;
endAngle?: number;
eventKey?: StringOrNumberOrCallback;
events?: EventPropTypeInterface<
string,
string[] | number[] | string | number
>[];
innerRadius?: number;
prependDefaultAxes?: boolean;
startAngle?: number;
style?: Pick & {
background?: VictoryStyleObject;
};
title?: string;
}