import React, {
ComponentType,
PropsWithoutRef,
Ref,
RefAttributes,
forwardRef,
useImperativeHandle,
useRef,
useState,
} from 'react';
import { memoize } from 'lodash';
import { FacetedData, FacetedPlotRef, PlotRef } from '../types/plots';
import { PlotProps } from './PlotlyPlot';
import { Modal } from '@veupathdb/coreui';
type ComponentWithPlotRef
= ComponentType<
PropsWithoutRef
& RefAttributes
>;
export interface FacetedPlotProps> {
data?: FacetedData;
component: ComponentWithPlotRef;
componentProps: P;
/** Provide modalComponentProps to activate click-to-expand
* These are the props the expanded plot inside the modal will receive
*/
modalComponentProps?: P;
// custom legend prop
checkedLegendItems?: string[];
}
export interface FacetedPlotPropsWithRef>
extends FacetedPlotProps {
facetedPlotRef?: Ref;
}
function renderFacetedPlot>(
props: FacetedPlotProps,
ref: Ref
) {
const {
data,
component: Component,
componentProps,
modalComponentProps,
checkedLegendItems,
} = props;
const plotRefs = useRef([]);
const [modalIsOpen, setModalIsOpen] = useState(false);
const [modalPlot, setModalPlot] = useState(null);
const contentPadding = 20;
useImperativeHandle(
ref,
() => {
const plotRefsLength = data?.facets.length ?? 0;
plotRefs.current = plotRefs.current.slice(0, plotRefsLength);
return plotRefs.current;
},
[data?.facets]
);
return (
<>
{componentProps.title}
{data?.facets.map(({ data, label }, index) => {
const sharedProps = {
data: data,
...componentProps,
// pass checkedLegendItems to PlotlyPlot
checkedLegendItems: checkedLegendItems,
showNoDataOverlay: data == null,
};
const divModalProps = modalComponentProps && {
onClick: () => {
setModalPlot(
);
setModalIsOpen(true);
},
title: 'Click to expand',
};
return (
{
if (plotInstance == null) {
delete plotRefs.current[index];
} else {
plotRefs.current[index] = plotInstance;
}
}}
displayLegend={false}
interactive={false}
title={label}
/>
);
})}
{modalComponentProps && modalIsOpen && (
{modalPlot}
)}
>
);
}
const makeFacetedPlotComponent = memoize(function >(
UnfacetedPlotComponent: ComponentWithPlotRef
) {
const FacetedPlotComponent = forwardRef<
FacetedPlotRef,
FacetedPlotProps
>(renderFacetedPlot);
FacetedPlotComponent.displayName = `FacetedPlotComponent(${
UnfacetedPlotComponent.displayName || UnfacetedPlotComponent.name
})`;
return FacetedPlotComponent;
});
export default function FacetedPlot>(
props: FacetedPlotPropsWithRef
) {
const FacetedPlotComponent = makeFacetedPlotComponent(props.component);
return ;
}