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 ; }