diff --git a/package.json b/package.json index b0d2efe5..9a860fa7 100644 --- a/package.json +++ b/package.json @@ -8,11 +8,13 @@ "url": "https://github.com/veupathdb/web-components.git" }, "dependencies": { + "@emotion/react": "^11.7.0", "@material-ui/core": "^4.11.2", "@material-ui/icons": "^4.11.2", "@material-ui/lab": "^4.0.0-alpha.57", "@types/d3": "^7.1.0", "@types/date-arithmetic": "^4.1.1", + "@veupathdb/core-components": "^0.2.46", "@visx/gradient": "^1.0.0", "@visx/group": "^1.0.0", "@visx/hierarchy": "^1.0.0", diff --git a/src/components/ContingencyTable.tsx b/src/components/ContingencyTable.tsx index d3807973..fc0112db 100644 --- a/src/components/ContingencyTable.tsx +++ b/src/components/ContingencyTable.tsx @@ -1,12 +1,12 @@ import { CSSProperties } from 'react'; -import { MosaicData } from '../types/plots/mosaic'; +import { MosaicPlotData } from '../types/plots/mosaicPlot'; import _ from 'lodash'; import { FacetedData } from '../types/plots'; import { isFaceted } from '../types/guards'; import Spinner from '../components/Spinner'; interface ContingencyTableProps { - data?: MosaicData | FacetedData; + data?: MosaicPlotData | FacetedData; independentVariable: string; dependentVariable: string; facetVariable?: string; diff --git a/src/plots/FacetedPlot.tsx b/src/plots/FacetedPlot.tsx index a8e41567..9580fdec 100644 --- a/src/plots/FacetedPlot.tsx +++ b/src/plots/FacetedPlot.tsx @@ -6,6 +6,7 @@ import React, { forwardRef, useImperativeHandle, useRef, + useState, } from 'react'; import { memoize } from 'lodash'; @@ -13,6 +14,8 @@ import { memoize } from 'lodash'; import { FacetedData, FacetedPlotRef, PlotRef } from '../types/plots'; import { PlotProps } from './PlotlyPlot'; +import { FullScreenModal } from '@veupathdb/core-components'; + type ComponentWithPlotRef

= ComponentType< PropsWithoutRef

& RefAttributes >; @@ -20,11 +23,20 @@ type ComponentWithPlotRef

= ComponentType< export interface FacetedPlotProps> { data?: FacetedData; component: ComponentWithPlotRef

; - props: P; + 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 @@ -32,10 +44,13 @@ function renderFacetedPlot>( const { data, component: Component, - props: componentProps, - checkedLegendItems: checkedLegendItems, + componentProps, + modalComponentProps, + checkedLegendItems, } = props; const plotRefs = useRef([]); + const [modalIsOpen, setModalIsOpen] = useState(false); + const [modalPlot, setModalPlot] = useState(null); useImperativeHandle( ref, @@ -60,27 +75,77 @@ function renderFacetedPlot>( overflow: 'auto', }} > - {data?.facets.map(({ data, label }, index) => ( - { - if (plotInstance == null) { - delete plotRefs.current[index]; - } else { - plotRefs.current[index] = plotInstance; - } - }} - key={index} - data={data} - title={label} - displayLegend={false} - interactive={false} + {data?.facets.map(({ data, label }, index) => { + const sharedProps = { + data: data, // pass checkedLegendItems to PlotlyPlot - checkedLegendItems={checkedLegendItems} - showNoDataOverlay={data == null} - /> - ))} + 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} + {...componentProps} + title={label} + /> +
+ ); + })} + {modalComponentProps && ( + + + {modalPlot} + + )} ); } @@ -101,7 +166,7 @@ const makeFacetedPlotComponent = memoize(function >( }); export default function FacetedPlot>( - props: FacetedPlotProps & { facetedPlotRef?: Ref } + props: FacetedPlotPropsWithRef ) { const FacetedPlotComponent = makeFacetedPlotComponent(props.component); diff --git a/src/plots/MosaicPlot.tsx b/src/plots/MosaicPlot.tsx index 5bf48286..9b2b8559 100644 --- a/src/plots/MosaicPlot.tsx +++ b/src/plots/MosaicPlot.tsx @@ -5,7 +5,7 @@ import { makePlotlyPlotComponent, PlotProps, } from './PlotlyPlot'; -import { MosaicData } from '../types/plots'; +import { MosaicPlotData } from '../types/plots'; import { PlotParams } from 'react-plotly.js'; import _ from 'lodash'; // util functions for handling long tick labels with ellipsis @@ -14,7 +14,7 @@ import { makeStyles } from '@material-ui/core/styles'; import { PlotSpacingDefault } from '../types/plots/addOns'; import { Layout } from 'plotly.js'; -export interface MosaicPlotProps extends PlotProps { +export interface MosaicPlotProps extends PlotProps { /** label for independent axis */ independentAxisLabel?: string; /** label for dependent axis */ @@ -24,7 +24,7 @@ export interface MosaicPlotProps extends PlotProps { showColumnLabels?: boolean; } -export const EmptyMosaicData: MosaicData = { +export const EmptyMosaicData: MosaicPlotData = { values: [[]], independentLabels: [], dependentLabels: [], @@ -127,11 +127,12 @@ const MosaicPlot = makePlotlyPlotComponent( maxIndependentTickLabelLength ); // Subtraction at end is due to x-axis automargin shrinking the plot - const plotHeight = + let plotHeight = containerHeight - marginTop - marginBottom - - 5 * longestIndependentTickLabelLength; + 8 * longestIndependentTickLabelLength; + if (!independentAxisLabel) plotHeight -= 20; // Calculate the legend trace group gap accordingly legendTraceGroupGap = ((plotHeight - defaultLegendItemHeight * data.dependentLabels.length) * diff --git a/src/plots/PlotlyPlot.tsx b/src/plots/PlotlyPlot.tsx index 26c79107..9bc1e42b 100644 --- a/src/plots/PlotlyPlot.tsx +++ b/src/plots/PlotlyPlot.tsx @@ -59,6 +59,8 @@ export interface PlotProps extends ColorPaletteAddon { storedIndependentAxisTickLabel?: string[]; /** list of checked legend items via checkbox input */ checkedLegendItems?: string[]; + /** A function to call each time after plotly renders the plot */ + onPlotlyRender?: PlotParams['onUpdate']; } const Plot = lazy(() => import('react-plotly.js')); @@ -99,6 +101,7 @@ function PlotlyPlot( storedIndependentAxisTickLabel, checkedLegendItems, colorPalette = ColorPaletteDefault, + onPlotlyRender, ...plotlyProps } = props; @@ -202,8 +205,9 @@ function PlotlyPlot( ); // ellipsis with tooltip for legend, legend title, and independent axis tick labels - const onUpdate = useCallback( - (_, graphDiv: Readonly) => { + const onRender = useCallback( + (figure, graphDiv: Readonly) => { + onPlotlyRender && onPlotlyRender(figure, graphDiv); // legend tooltip // remove pre-existing title to avoid duplicates select(graphDiv) @@ -291,6 +295,7 @@ function PlotlyPlot( } }, [ + onPlotlyRender, storedLegendList, legendTitle, maxLegendTitleTextLength, @@ -299,6 +304,14 @@ function PlotlyPlot( ] ); + const onInitialized = useCallback( + (figure, graphDiv: Readonly) => { + onRender(figure, graphDiv); + sharedPlotCreation.run(); + }, + [onRender, sharedPlotCreation.run] + ); + const finalData = useMemo(() => { return data.map((d) => ({ ...d, @@ -352,8 +365,8 @@ function PlotlyPlot( style={{ width: '100%', height: '100%' }} config={finalConfig} // use onUpdate event handler for legend tooltip - onUpdate={onUpdate} - onInitialized={sharedPlotCreation.run} + onUpdate={onRender} + onInitialized={onInitialized} /> {showNoDataOverlay && (
, + 'component' +>; + +const FacetedBarplot = (facetedBarplotProps: FacetedBarplotProps) => { + const { componentProps } = facetedBarplotProps; + + return ( + + ); +}; + +export default FacetedBarplot; diff --git a/src/plots/facetedPlots/FacetedBoxplot.tsx b/src/plots/facetedPlots/FacetedBoxplot.tsx new file mode 100644 index 00000000..5338003f --- /dev/null +++ b/src/plots/facetedPlots/FacetedBoxplot.tsx @@ -0,0 +1,43 @@ +import Boxplot, { BoxplotProps } from '../Boxplot'; +import FacetedPlot, { FacetedPlotPropsWithRef } from '../FacetedPlot'; +import { BoxplotData } from '../../types/plots'; + +export const defaultContainerStyles: BoxplotProps['containerStyles'] = { + height: 300, + width: 375, + marginLeft: '0.75rem', + marginBottom: '0.25rem', + border: '1px solid #dedede', + boxShadow: '1px 1px 4px #00000066', +}; + +export const defaultSpacingOptions: BoxplotProps['spacingOptions'] = { + marginRight: 15, + marginLeft: 15, + marginBottom: 10, + marginTop: 50, +}; + +type FacetedBoxplotProps = Omit< + FacetedPlotPropsWithRef, + 'component' +>; + +const FacetedBoxplot = (facetedBoxplotProps: FacetedBoxplotProps) => { + const { componentProps } = facetedBoxplotProps; + + return ( + + ); +}; + +export default FacetedBoxplot; diff --git a/src/plots/facetedPlots/FacetedHeatmap.tsx b/src/plots/facetedPlots/FacetedHeatmap.tsx new file mode 100644 index 00000000..ce03440a --- /dev/null +++ b/src/plots/facetedPlots/FacetedHeatmap.tsx @@ -0,0 +1,42 @@ +import Heatmap, { HeatmapProps } from '../Heatmap'; +import FacetedPlot, { FacetedPlotPropsWithRef } from '../FacetedPlot'; +import { HeatmapData } from '../../types/plots'; + +export const defaultContainerStyles: HeatmapProps['containerStyles'] = { + height: 300, + width: 375, + marginLeft: '0.75rem', + border: '1px solid #dedede', + boxShadow: '1px 1px 4px #00000066', +}; + +export const defaultSpacingOptions: HeatmapProps['spacingOptions'] = { + marginRight: 10, + marginLeft: 25, + marginBottom: 40, + marginTop: 60, +}; + +type FacetedHeatmapProps = Omit< + FacetedPlotPropsWithRef, + 'component' +>; + +const FacetedHeatmap = (facetedHeatmapProps: FacetedHeatmapProps) => { + const { componentProps } = facetedHeatmapProps; + + return ( + + ); +}; + +export default FacetedHeatmap; diff --git a/src/plots/facetedPlots/FacetedHistogram.tsx b/src/plots/facetedPlots/FacetedHistogram.tsx new file mode 100644 index 00000000..1960e311 --- /dev/null +++ b/src/plots/facetedPlots/FacetedHistogram.tsx @@ -0,0 +1,43 @@ +import Histogram, { HistogramProps } from '../Histogram'; +import FacetedPlot, { FacetedPlotPropsWithRef } from '../FacetedPlot'; +import { HistogramData } from '../../types/plots'; + +export const defaultContainerStyles: HistogramProps['containerStyles'] = { + height: 300, + width: 375, + marginLeft: '0.75rem', + marginBottom: '0.25rem', + border: '1px solid #dedede', + boxShadow: '1px 1px 4px #00000066', +}; + +export const defaultSpacingOptions: HistogramProps['spacingOptions'] = { + marginRight: 10, + marginLeft: 10, + marginBottom: 10, + marginTop: 50, +}; + +type FacetedHistogramProps = Omit< + FacetedPlotPropsWithRef, + 'component' +>; + +const FacetedHistogram = (facetedHistogramProps: FacetedHistogramProps) => { + const { componentProps } = facetedHistogramProps; + + return ( + + ); +}; + +export default FacetedHistogram; diff --git a/src/plots/facetedPlots/FacetedMosaicPlot.tsx b/src/plots/facetedPlots/FacetedMosaicPlot.tsx new file mode 100644 index 00000000..eb6c57cc --- /dev/null +++ b/src/plots/facetedPlots/FacetedMosaicPlot.tsx @@ -0,0 +1,43 @@ +import MosaicPlot, { MosaicPlotProps } from '../MosaicPlot'; +import FacetedPlot, { FacetedPlotPropsWithRef } from '../FacetedPlot'; +import { MosaicPlotData } from '../../types/plots'; + +export const defaultContainerStyles: MosaicPlotProps['containerStyles'] = { + height: 360, + width: 750 / 1.45, + marginLeft: '0.75rem', + marginBottom: '0.25rem', + border: '1px solid #dedede', + boxShadow: '1px 1px 4px #00000066', +}; + +export const defaultSpacingOptions: MosaicPlotProps['spacingOptions'] = { + marginRight: 15, + marginLeft: 15, + marginBottom: 10, + marginTop: 50, +}; + +type FacetedMosaicPlotProps = Omit< + FacetedPlotPropsWithRef, + 'component' +>; + +const FacetedMosaicPlot = (facetedMosaicPlotProps: FacetedMosaicPlotProps) => { + const { componentProps } = facetedMosaicPlotProps; + + return ( + + ); +}; + +export default FacetedMosaicPlot; diff --git a/src/plots/facetedPlots/FacetedPiePlot.tsx b/src/plots/facetedPlots/FacetedPiePlot.tsx new file mode 100644 index 00000000..0a7ad80f --- /dev/null +++ b/src/plots/facetedPlots/FacetedPiePlot.tsx @@ -0,0 +1,61 @@ +import PiePlot, { PiePlotProps } from '../PiePlot'; +import FacetedPlot, { FacetedPlotPropsWithRef } from '../FacetedPlot'; +import { PiePlotData } from '../../types/plots'; +import { useCallback } from 'react'; +import { select } from 'd3'; + +export const defaultContainerStyles: PiePlotProps['containerStyles'] = { + height: 300, + width: 375, + marginLeft: '0.75rem', + border: '1px solid #dedede', + boxShadow: '1px 1px 4px #00000066', +}; + +export const defaultSpacingOptions: PiePlotProps['spacingOptions'] = { + marginRight: 10, + marginLeft: 10, + marginBottom: 10, + marginTop: 50, +}; + +type FacetedPiePlotProps = Omit< + FacetedPlotPropsWithRef, + 'component' +>; + +const FacetedPiePlot = (facetedPiePlotProps: FacetedPiePlotProps) => { + const { componentProps } = facetedPiePlotProps; + const onPlotlyRender = useCallback((_, graphDiv) => { + // Replace each slice DOM node with a copy of itself. + // This removes the existing click event handler, which + // otherwise blocks the click handler that opens the modal + const parentNode = select(graphDiv).select('g.trace'); + const sliceNodes = parentNode.selectAll('g.slice'); + sliceNodes.each(function () { + const sliceNode = select(this); + const clone = sliceNode.clone(true); + parentNode.insert( + () => clone.node(), + () => this + ); + sliceNode.remove(); + }); + }, []); + + return ( + + ); +}; + +export default FacetedPiePlot; diff --git a/src/plots/facetedPlots/FacetedXYPlot.tsx b/src/plots/facetedPlots/FacetedXYPlot.tsx new file mode 100644 index 00000000..36394fdd --- /dev/null +++ b/src/plots/facetedPlots/FacetedXYPlot.tsx @@ -0,0 +1,43 @@ +import XYPlot, { XYPlotProps } from '../XYPlot'; +import FacetedPlot, { FacetedPlotPropsWithRef } from '../FacetedPlot'; +import { XYPlotData } from '../../types/plots'; + +export const defaultContainerStyles: XYPlotProps['containerStyles'] = { + height: 300, + width: 750 / 1.75, + marginLeft: '0.75rem', + marginBottom: '0.25rem', + border: '1px solid #dedede', + boxShadow: '1px 1px 4px #00000066', +}; + +export const defaultSpacingOptions: XYPlotProps['spacingOptions'] = { + marginRight: 20, + marginLeft: 50, + marginBottom: 40, + marginTop: 50, +}; + +type FacetedXYPlotProps = Omit< + FacetedPlotPropsWithRef, + 'component' +>; + +const FacetedXYPlot = (facetedXYPlotProps: FacetedXYPlotProps) => { + const { componentProps } = facetedXYPlotProps; + + return ( + + ); +}; + +export default FacetedXYPlot; diff --git a/src/stories/plots/Barplot.stories.tsx b/src/stories/plots/Barplot.stories.tsx index 1fe8d09a..f5adb3a9 100644 --- a/src/stories/plots/Barplot.stories.tsx +++ b/src/stories/plots/Barplot.stories.tsx @@ -1,5 +1,7 @@ import { Story, Meta } from '@storybook/react/types-6-0'; import Barplot, { BarplotProps } from '../../plots/Barplot'; +import { FacetedData, BarplotData } from '../../types/plots'; +import FacetedBarplot from '../../plots/facetedPlots/FacetedBarplot'; export default { title: 'Plots/Barplot', @@ -52,3 +54,76 @@ NoDataOverlay.args = { showNoDataOverlay: true, title: 'Awesomeness of animals stratified by domestication', }; + +/** + * FACETING + */ + +const facetedData: FacetedData = { + facets: [ + { + label: 'indoors', + data: dataSet, + }, + { + label: 'outdoors', + data: dataSet, + }, + { + label: 'indoors', + data: dataSet, + }, + { + label: 'outdoors', + data: dataSet, + }, + { + label: 'indoors', + data: dataSet, + }, + { + label: 'outdoors', + }, + { + label: 'No data', + }, + ], +}; + +interface FacetedStoryProps { + data: FacetedData; + componentProps: BarplotProps; + modalComponentProps: BarplotProps; +} + +const FacetedTemplate: Story = ({ + data, + componentProps, + modalComponentProps, +}) => ( + +); + +export const Faceted = FacetedTemplate.bind({}); +Faceted.args = { + data: facetedData, + componentProps: { + title: 'indoor and outdoor pets', + containerStyles: { + width: 300, + height: 300, + border: '1px solid #dadada', + }, + }, + modalComponentProps: { + containerStyles: { + width: '100%', + height: '100%', + margin: 'auto', + }, + }, +}; diff --git a/src/stories/plots/Boxplot.stories.tsx b/src/stories/plots/Boxplot.stories.tsx index df953bda..92394348 100755 --- a/src/stories/plots/Boxplot.stories.tsx +++ b/src/stories/plots/Boxplot.stories.tsx @@ -1,6 +1,8 @@ import React from 'react'; import { Meta, Story } from '@storybook/react'; import Boxplot, { BoxplotProps } from '../../plots/Boxplot'; +import { FacetedData, BoxplotData } from '../../types/plots'; +import FacetedBoxplot from '../../plots/facetedPlots/FacetedBoxplot'; export default { title: 'Plots/Boxplot', @@ -390,3 +392,61 @@ function storyArgTypes(args: any): any { }; } } + +/** + * FACETING + */ + +const facetedData: FacetedData = { + facets: [ + { + label: 'Low income', + data: multipleData.series, + }, + { + label: 'Medium income', + data: multipleData.series, + }, + { + label: 'High income', + data: multipleData.series, + }, + { + label: 'Even higher income', + }, + { + label: 'No data', + }, + ], +}; + +interface FacetedStoryProps { + data: FacetedData; + componentProps: BoxplotProps; + modalComponentProps?: BoxplotProps; +} + +const FacetedTemplate: Story = ({ + data, + componentProps, + modalComponentProps, +}) => ( + +); + +export const Faceted = FacetedTemplate.bind({}); +Faceted.args = { + data: facetedData, + componentProps: { + title: 'Number of rooms (faceted)', + containerStyles: { + width: 300, + height: 300, + border: '1px solid #dadada', + }, + }, +}; diff --git a/src/stories/plots/Heatmap.stories.tsx b/src/stories/plots/Heatmap.stories.tsx index e3dd4ccc..764b446a 100644 --- a/src/stories/plots/Heatmap.stories.tsx +++ b/src/stories/plots/Heatmap.stories.tsx @@ -1,6 +1,8 @@ import React from 'react'; import Heatmap, { HeatmapProps } from '../../plots/Heatmap'; import { Meta, Story } from '@storybook/react'; +import { FacetedData, HeatmapData } from '../../types/plots'; +import FacetedHeatmap from '../../plots/facetedPlots/FacetedHeatmap'; export default { title: 'Plots/Heatmap', @@ -12,17 +14,19 @@ export default { const Template: Story = (args) => ; +const numericData = { + xLabels: [1, 2, 3, 4], + yLabels: [1, 2, 3], + values: [ + [1, 20, 40, 30], + [20, 0, 60, 15], + [30, 60, 0, 50], + ], +}; + export const NumericAxes = Template.bind({}); NumericAxes.args = { - data: { - xLabels: [1, 2, 3, 4], - yLabels: [1, 2, 3], - values: [ - [1, 20, 40, 30], - [20, 0, 60, 15], - [30, 60, 0, 50], - ], - }, + data: numericData, xAxisLabel: 'Number of pets', yAxisLabel: 'Number of children', showValues: false, @@ -55,3 +59,63 @@ export const EmptyLoading = Template.bind({}); EmptyLoading.args = { showSpinner: true, }; + +/** + * FACETING + */ + +const facetedData: FacetedData = { + facets: [ + { + label: 'Kenya', + data: numericData, + }, + { + label: 'Zimbabwe', + data: numericData, + }, + { + label: 'South Africa', + data: numericData, + }, + { + label: 'Wakanda', + }, + { + label: 'No data', + }, + ], +}; + +interface FacetedStoryProps { + data: FacetedData; + componentProps: HeatmapProps; + modalComponentProps: HeatmapProps; +} + +const FacetedTemplate: Story = ({ + data, + componentProps, + modalComponentProps, +}) => ( + +); + +export const Faceted = FacetedTemplate.bind({}); +Faceted.args = { + data: facetedData, + componentProps: { + title: 'Number of children vs Number of pets (faceted)', + }, + modalComponentProps: { + containerStyles: { + width: '100%', + height: '100%', + margin: 'auto', + }, + }, +}; diff --git a/src/stories/plots/Histogram.stories.tsx b/src/stories/plots/Histogram.stories.tsx index f0ef12ac..ff026400 100644 --- a/src/stories/plots/Histogram.stories.tsx +++ b/src/stories/plots/Histogram.stories.tsx @@ -12,7 +12,12 @@ import HistogramControls from '../../components/plotControls/HistogramControls'; import AxisRangeControl from '../../components/plotControls/AxisRangeControl'; import { binDailyCovidStats } from '../api/covidData'; import { binGithubEventDates } from '../api/githubDates'; -import { HistogramData, AxisTruncationConfig } from '../../types/plots'; +import { + HistogramData, + AxisTruncationConfig, + FacetedData, +} from '../../types/plots'; +import FacetedHistogram from '../../plots/facetedPlots/FacetedHistogram'; export default { title: 'Plots/Histogram', @@ -451,24 +456,26 @@ const TemplateStaticWithRangeControls: Story = (args) => { ); }; +const staticData = { + series: [ + { + name: 'penguins', + // added 0 for testing purpose + bins: [0, 42, 11, 99, 23, 7, 9].map((num, index) => ({ + binStart: index + 1, + binEnd: index + 2, + binLabel: `${index + 1} to ${index + 2}`, + count: num, + })), + }, + ], +}; + export const StaticDataWithRangeControls = TemplateStaticWithRangeControls.bind( {} ); StaticDataWithRangeControls.args = { - data: { - series: [ - { - name: 'penguins', - // added 0 for testing purpose - bins: [0, 42, 11, 99, 23, 7, 9].map((num, index) => ({ - binStart: index + 1, - binEnd: index + 2, - binLabel: `${index + 1} to ${index + 2}`, - count: num, - })), - }, - ], - }, + data: staticData, interactive: true, }; @@ -491,3 +498,73 @@ ShowValues.args = { interactive: true, showValues: true, }; + +/** + * FACETING + */ + +const facetedData: FacetedData = { + facets: [ + { + label: 'Emperor', + data: staticData, + }, + { + label: 'Gentoo', + data: staticData, + }, + { + label: 'Rockhopper', + data: staticData, + }, + { + label: 'African', + data: staticData, + }, + { + label: 'Madagascar', + }, + { + label: 'No data', + data: staticData, + }, + ], +}; + +interface FacetedStoryProps { + data: FacetedData; + componentProps: HistogramProps; + modalComponentProps: HistogramProps; +} + +const FacetedTemplate: Story = ({ + data, + componentProps, + modalComponentProps, +}) => ( + +); + +export const Faceted = FacetedTemplate.bind({}); +Faceted.args = { + data: facetedData, + componentProps: { + title: 'Penguins', + containerStyles: { + width: 300, + height: 300, + border: '1px solid #dadada', + }, + }, + modalComponentProps: { + containerStyles: { + width: '100%', + height: '100%', + margin: 'auto', + }, + }, +}; diff --git a/src/stories/plots/MosaicPlot.stories.tsx b/src/stories/plots/MosaicPlot.stories.tsx index 687a84ef..222dae34 100644 --- a/src/stories/plots/MosaicPlot.stories.tsx +++ b/src/stories/plots/MosaicPlot.stories.tsx @@ -1,6 +1,8 @@ import React from 'react'; import { Meta, Story } from '@storybook/react'; import MosaicPlot, { MosaicPlotProps } from '../../plots/MosaicPlot'; +import { FacetedData, MosaicPlotData } from '../../types/plots'; +import FacetedMosaicPlot from '../../plots/facetedPlots/FacetedMosaicPlot'; export default { title: 'Plots/Mosaic', @@ -47,19 +49,21 @@ TwoByThree.args = { displayLegend: false, }; +const fourByThreeData = { + values: [ + [52, 15, 35], + [15, 40, 50], + [20, 15, 7], + [22, 30, 10], + ], + independentLabels: ['Mercury', 'Venus', 'Mars'], + dependentLabels: ['Nitrogen', 'Oxygen', 'Hydrogen', 'Other'], +}; + export const FourByThree = Template.bind({}); FourByThree.args = { ...defaults, - data: { - values: [ - [52, 15, 35], - [15, 40, 50], - [20, 15, 7], - [22, 30, 10], - ], - independentLabels: ['Mercury', 'Venus', 'Mars'], - dependentLabels: ['Nitrogen', 'Oxygen', 'Hydrogen', 'Other'], - }, + data: fourByThreeData, independentAxisLabel: 'Planet', dependentAxisLabel: 'Atmospheric makeup', interactive: true, @@ -72,3 +76,68 @@ export const EmptyDataLoading = Template.bind({}); EmptyDataLoading.args = { showSpinner: true, }; + +/** + * FACETING + */ + +const facetedData: FacetedData = { + facets: [ + { + label: '10 bya', + }, + { + label: '4.5 bya', + data: fourByThreeData, + }, + { + label: '2 bya', + data: fourByThreeData, + }, + { + label: 'Today', + data: fourByThreeData, + }, + { + label: 'No data', + }, + ], +}; + +interface FacetedStoryProps { + data: FacetedData; + componentProps: MosaicPlotProps; + modalComponentProps: MosaicPlotProps; +} + +const FacetedTemplate: Story = ({ + data, + componentProps, + modalComponentProps, +}) => ( + +); + +export const Faceted = FacetedTemplate.bind({}); +Faceted.args = { + data: facetedData, + componentProps: { + title: 'Atmospheric makeup of planets over time', + containerStyles: { + width: 300, + height: 300, + border: '1px solid #dadada', + }, + }, + modalComponentProps: { + containerStyles: { + width: '100%', + height: '100%', + margin: 'auto', + }, + }, +}; diff --git a/src/stories/plots/PiePlot.stories.tsx b/src/stories/plots/PiePlot.stories.tsx index a25794b2..506398e4 100644 --- a/src/stories/plots/PiePlot.stories.tsx +++ b/src/stories/plots/PiePlot.stories.tsx @@ -2,7 +2,7 @@ import { Story } from '@storybook/react/types-6-0'; import PiePlot, { PiePlotProps } from '../../plots/PiePlot'; import { FacetedData, PiePlotData } from '../../types/plots'; -import FacetedPlot from '../../plots/FacetedPlot'; +import FacetedPiePlot from '../../plots/facetedPlots/FacetedPiePlot'; import { DARK_GRAY, DARK_GREEN, @@ -156,238 +156,83 @@ EmptyLoading.args = { * FACETING */ -const facetedData: FacetedData = { - facets: [ - { - label: 'indoors', - data: { - slices: [ - { - value: 25, - label: 'dogs', - }, - { - value: 10, - label: 'cats', - }, - ], - }, - }, - { - label: 'outdoors', - data: { - slices: [ - { - value: 5, - label: 'dogs', - }, - { - value: 33, - label: 'cats', - }, - ], - }, - }, - { - label: 'indoors', - data: { - slices: [ - { - value: 25, - label: 'dogs', - }, - { - value: 10, - label: 'cats', - }, - ], - }, - }, - { - label: 'outdoors', - data: { - slices: [ - { - value: 5, - label: 'dogs', - }, - { - value: 33, - label: 'cats', - }, - ], +const facetSeries1 = { + label: 'indoors', + data: { + slices: [ + { + value: 25, + label: 'dogs', }, - }, - { - label: 'indoors', - data: { - slices: [ - { - value: 25, - label: 'dogs', - }, - { - value: 10, - label: 'cats', - }, - ], - }, - }, - { - label: 'outdoors', - data: { - slices: [ - { - value: 5, - label: 'dogs', - }, - { - value: 33, - label: 'cats', - }, - ], - }, - }, - { - label: 'indoors', - data: { - slices: [ - { - value: 25, - label: 'dogs', - }, - { - value: 10, - label: 'cats', - }, - ], - }, - }, - { - label: 'outdoors', - data: { - slices: [ - { - value: 5, - label: 'dogs', - }, - { - value: 33, - label: 'cats', - }, - ], + { + value: 10, + label: 'cats', }, - }, - { - label: 'indoors', - data: { - slices: [ - { - value: 25, - label: 'dogs', - }, - { - value: 10, - label: 'cats', - }, - ], - }, - }, - { - label: 'outdoors', - data: { - slices: [ - { - value: 5, - label: 'dogs', - }, - { - value: 33, - label: 'cats', - }, - ], - }, - }, - { - label: 'indoors', - data: { - slices: [ - { - value: 25, - label: 'dogs', - }, - { - value: 10, - label: 'cats', - }, - ], + ], + }, +}; + +const facetSeries2 = { + label: 'outdoors', + data: { + slices: [ + { + value: 5, + label: 'dogs', }, - }, - { - label: 'outdoors', - data: { - slices: [ - { - value: 5, - label: 'dogs', - }, - { - value: 33, - label: 'cats', - }, - ], + { + value: 33, + label: 'cats', }, - }, + ], + }, +}; + +const facetedData: FacetedData = { + facets: [ + facetSeries1, + facetSeries2, + facetSeries1, + facetSeries2, + facetSeries1, + facetSeries2, + facetSeries1, + facetSeries2, + facetSeries1, + facetSeries2, + facetSeries1, + facetSeries2, { label: 'indoors', - data: { - slices: [ - { - value: 25, - label: 'dogs', - }, - { - value: 10, - label: 'cats', - }, - ], - }, }, { - label: 'outdoors', - data: { - slices: [ - { - value: 5, - label: 'dogs', - }, - { - value: 33, - label: 'cats', - }, - ], - }, + label: 'No data', }, ], }; interface FacetedStoryProps { data: FacetedData; - props: PiePlotProps; + componentProps: PiePlotProps; + modalComponentProps: PiePlotProps; } -const FacetedTemplate: Story = ({ data, props }) => ( - +const FacetedTemplate: Story = ({ + data, + componentProps, + modalComponentProps, +}) => ( + ); export const Faceted = FacetedTemplate.bind({}); Faceted.args = { data: facetedData, - props: { + componentProps: { title: 'indoor and outdoor pets', containerStyles: { width: 300, @@ -395,4 +240,11 @@ Faceted.args = { border: '1px solid #dadada', }, }, + modalComponentProps: { + containerStyles: { + width: '100%', + height: '100%', + margin: 'auto', + }, + }, }; diff --git a/src/stories/plots/XYPlot.stories.tsx b/src/stories/plots/XYPlot.stories.tsx index 97bbf1c0..e2b51aaf 100755 --- a/src/stories/plots/XYPlot.stories.tsx +++ b/src/stories/plots/XYPlot.stories.tsx @@ -5,6 +5,8 @@ import { min, max, lte, gte } from 'lodash'; import { Story, Meta } from '@storybook/react/types-6-0'; // test to use RadioButtonGroup directly instead of XYPlotControls import RadioButtonGroup from '../../components/widgets/RadioButtonGroup'; +import { FacetedData, XYPlotData } from '../../types/plots'; +import FacetedXYPlot from '../../plots/facetedPlots/FacetedXYPlot'; export default { title: 'Plots/XYPlot', @@ -1146,3 +1148,68 @@ function getBounds( return { yUpperValues, yLowerValues }; } + +/** + * FACETING + */ + +const facetedData: FacetedData = { + facets: [ + { + label: 'Facet 1', + data: dataSetProcess, + }, + { + label: 'Facet 2', + data: dataSetProcess, + }, + { + label: 'Facet 3', + data: dataSetProcess, + }, + { + label: 'Facet 400', + }, + { + label: 'No data', + }, + ], +}; + +interface FacetedStoryProps { + data: FacetedData; + componentProps: XYPlotProps; + modalComponentProps: XYPlotProps; +} + +const FacetedTemplate: Story = ({ + data, + componentProps, + modalComponentProps, +}) => ( + +); + +export const Faceted = FacetedTemplate.bind({}); +Faceted.args = { + data: facetedData, + componentProps: { + title: 'Faceted XYPlot', + containerStyles: { + width: 300, + height: 300, + border: '1px solid #dadada', + }, + }, + modalComponentProps: { + containerStyles: { + width: '100%', + height: '100%', + margin: 'auto', + }, + }, +}; diff --git a/src/types/plots/index.ts b/src/types/plots/index.ts index fb9d36d4..3c078534 100644 --- a/src/types/plots/index.ts +++ b/src/types/plots/index.ts @@ -10,7 +10,7 @@ import { BoxplotData } from './boxplot'; import { XYPlotData } from './xyplot'; import { BarplotData } from './barplot'; import { HeatmapData } from './heatmap'; -import { MosaicData } from './mosaic'; +import { MosaicPlotData } from './mosaicPlot'; import { BirdsEyePlotData } from './birdseyeplot'; /** @@ -43,7 +43,7 @@ export type UnionOfPlotDataTypes = | XYPlotData | BarplotData | HeatmapData - | MosaicData + | MosaicPlotData | BirdsEyePlotData; export * from './addOns'; @@ -55,5 +55,5 @@ export * from './boxplot'; export * from './xyplot'; export * from './barplot'; export * from './heatmap'; -export * from './mosaic'; +export * from './mosaicPlot'; export * from './birdseyeplot'; diff --git a/src/types/plots/mosaic.ts b/src/types/plots/mosaicPlot.ts similarity index 85% rename from src/types/plots/mosaic.ts rename to src/types/plots/mosaicPlot.ts index 1527e29f..fe5f4d7c 100644 --- a/src/types/plots/mosaic.ts +++ b/src/types/plots/mosaicPlot.ts @@ -1,4 +1,4 @@ -export type MosaicData = { +export type MosaicPlotData = { // N columns, M rows values: Array>; // MxN (M = outerLength; N = innerLength) independentLabels: Array; // N diff --git a/yarn.lock b/yarn.lock index 66050b1c..1fea0380 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1516,6 +1516,17 @@ "@emotion/utils" "0.11.3" "@emotion/weak-memoize" "0.2.5" +"@emotion/cache@^11.6.0": + version "11.6.0" + resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.6.0.tgz#65fbdbbe4382f1991d8b20853c38e63ecccec9a1" + integrity sha512-ElbsWY1KMwEowkv42vGo0UPuLgtPYfIs9BxxVrmvsaJVvktknsHYYlx5NQ5g6zLDcOTyamlDc7FkRg2TAcQDKQ== + dependencies: + "@emotion/memoize" "^0.7.4" + "@emotion/sheet" "^1.1.0" + "@emotion/utils" "^1.0.0" + "@emotion/weak-memoize" "^0.2.5" + stylis "^4.0.10" + "@emotion/core@^10.0.9", "@emotion/core@^10.1.1": version "10.1.1" resolved "https://registry.yarnpkg.com/@emotion/core/-/core-10.1.1.tgz#c956c1365f2f2481960064bcb8c4732e5fb612c3" @@ -1554,6 +1565,24 @@ resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.4.tgz#19bf0f5af19149111c40d98bb0cf82119f5d9eeb" integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw== +"@emotion/memoize@^0.7.4": + version "0.7.5" + resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.5.tgz#2c40f81449a4e554e9fc6396910ed4843ec2be50" + integrity sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ== + +"@emotion/react@^11.7.0": + version "11.7.0" + resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.7.0.tgz#b179da970ac0e8415de3ac165deadf8d9c4bf89f" + integrity sha512-WL93hf9+/2s3cA1JVJlz8+Uy6p6QWukqQFOm2OZO5ki51hfucHMOmbSjiyC3t2Y4RI8XUmBoepoc/24ny/VBbA== + dependencies: + "@babel/runtime" "^7.13.10" + "@emotion/cache" "^11.6.0" + "@emotion/serialize" "^1.0.2" + "@emotion/sheet" "^1.1.0" + "@emotion/utils" "^1.0.0" + "@emotion/weak-memoize" "^0.2.5" + hoist-non-react-statics "^3.3.1" + "@emotion/serialize@^0.11.15", "@emotion/serialize@^0.11.16": version "0.11.16" resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-0.11.16.tgz#dee05f9e96ad2fb25a5206b6d759b2d1ed3379ad" @@ -1565,11 +1594,27 @@ "@emotion/utils" "0.11.3" csstype "^2.5.7" +"@emotion/serialize@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.0.2.tgz#77cb21a0571c9f68eb66087754a65fa97bfcd965" + integrity sha512-95MgNJ9+/ajxU7QIAruiOAdYNjxZX7G2mhgrtDWswA21VviYIRP1R5QilZ/bDY42xiKsaktP4egJb3QdYQZi1A== + dependencies: + "@emotion/hash" "^0.8.0" + "@emotion/memoize" "^0.7.4" + "@emotion/unitless" "^0.7.5" + "@emotion/utils" "^1.0.0" + csstype "^3.0.2" + "@emotion/sheet@0.9.4": version "0.9.4" resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-0.9.4.tgz#894374bea39ec30f489bbfc3438192b9774d32e5" integrity sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA== +"@emotion/sheet@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.1.0.tgz#56d99c41f0a1cda2726a05aa6a20afd4c63e58d2" + integrity sha512-u0AX4aSo25sMAygCuQTzS+HsImZFuS8llY8O7b9MDRzbJM0kVJlAz6KNDqcG7pOuQZJmj/8X/rAW+66kMnMW+g== + "@emotion/styled-base@^10.0.27": version "10.0.31" resolved "https://registry.yarnpkg.com/@emotion/styled-base/-/styled-base-10.0.31.tgz#940957ee0aa15c6974adc7d494ff19765a2f742a" @@ -1593,7 +1638,7 @@ resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.8.5.tgz#deacb389bd6ee77d1e7fcaccce9e16c5c7e78e04" integrity sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ== -"@emotion/unitless@0.7.5": +"@emotion/unitless@0.7.5", "@emotion/unitless@^0.7.5": version "0.7.5" resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed" integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== @@ -1603,7 +1648,12 @@ resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-0.11.3.tgz#a759863867befa7e583400d322652a3f44820924" integrity sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw== -"@emotion/weak-memoize@0.2.5": +"@emotion/utils@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.0.0.tgz#abe06a83160b10570816c913990245813a2fd6af" + integrity sha512-mQC2b3XLDs6QCW+pDQDiyO/EdGZYOygE8s5N5rrzjSI4M3IejPE/JPndCBwRT9z982aqQNi6beWs1UeayrQxxA== + +"@emotion/weak-memoize@0.2.5", "@emotion/weak-memoize@^0.2.5": version "0.2.5" resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46" integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA== @@ -1724,6 +1774,24 @@ react-is "^16.8.0 || ^17.0.0" react-transition-group "^4.4.0" +"@material-ui/core@^4.12.3": + version "4.12.3" + resolved "https://registry.yarnpkg.com/@material-ui/core/-/core-4.12.3.tgz#80d665caf0f1f034e52355c5450c0e38b099d3ca" + integrity sha512-sdpgI/PL56QVsEJldwEe4FFaFTLUqN+rd7sSZiRCdx2E/C7z5yK0y/khAWVBH24tXwto7I1hCzNWfJGZIYJKnw== + dependencies: + "@babel/runtime" "^7.4.4" + "@material-ui/styles" "^4.11.4" + "@material-ui/system" "^4.12.1" + "@material-ui/types" "5.1.0" + "@material-ui/utils" "^4.11.2" + "@types/react-transition-group" "^4.2.0" + clsx "^1.0.4" + hoist-non-react-statics "^3.3.2" + popper.js "1.16.1-lts" + prop-types "^15.7.2" + react-is "^16.8.0 || ^17.0.0" + react-transition-group "^4.4.0" + "@material-ui/icons@^4.11.2": version "4.11.2" resolved "https://registry.yarnpkg.com/@material-ui/icons/-/icons-4.11.2.tgz#b3a7353266519cd743b6461ae9fdfcb1b25eb4c5" @@ -1764,6 +1832,28 @@ jss-plugin-vendor-prefixer "^10.0.3" prop-types "^15.7.2" +"@material-ui/styles@^4.11.4": + version "4.11.4" + resolved "https://registry.yarnpkg.com/@material-ui/styles/-/styles-4.11.4.tgz#eb9dfccfcc2d208243d986457dff025497afa00d" + integrity sha512-KNTIZcnj/zprG5LW0Sao7zw+yG3O35pviHzejMdcSGCdWbiO8qzRgOYL8JAxAsWBKOKYwVZxXtHWaB5T2Kvxew== + dependencies: + "@babel/runtime" "^7.4.4" + "@emotion/hash" "^0.8.0" + "@material-ui/types" "5.1.0" + "@material-ui/utils" "^4.11.2" + clsx "^1.0.4" + csstype "^2.5.2" + hoist-non-react-statics "^3.3.2" + jss "^10.5.1" + jss-plugin-camel-case "^10.5.1" + jss-plugin-default-unit "^10.5.1" + jss-plugin-global "^10.5.1" + jss-plugin-nested "^10.5.1" + jss-plugin-props-sort "^10.5.1" + jss-plugin-rule-value-function "^10.5.1" + jss-plugin-vendor-prefixer "^10.5.1" + prop-types "^15.7.2" + "@material-ui/system@^4.11.2": version "4.11.2" resolved "https://registry.yarnpkg.com/@material-ui/system/-/system-4.11.2.tgz#7f0a754bba3673ed5fdbfa02fe438096c104b1f6" @@ -1774,7 +1864,17 @@ csstype "^2.5.2" prop-types "^15.7.2" -"@material-ui/types@^5.1.0": +"@material-ui/system@^4.12.1": + version "4.12.1" + resolved "https://registry.yarnpkg.com/@material-ui/system/-/system-4.12.1.tgz#2dd96c243f8c0a331b2bb6d46efd7771a399707c" + integrity sha512-lUdzs4q9kEXZGhbN7BptyiS1rLNHe6kG9o8Y307HCvF4sQxbCgpL2qi+gUk+yI8a2DNk48gISEQxoxpgph0xIw== + dependencies: + "@babel/runtime" "^7.4.4" + "@material-ui/utils" "^4.11.2" + csstype "^2.5.2" + prop-types "^15.7.2" + +"@material-ui/types@5.1.0", "@material-ui/types@^5.1.0": version "5.1.0" resolved "https://registry.yarnpkg.com/@material-ui/types/-/types-5.1.0.tgz#efa1c7a0b0eaa4c7c87ac0390445f0f88b0d88f2" integrity sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A== @@ -3864,6 +3964,18 @@ resolved "https://registry.yarnpkg.com/@veupathdb/browserslist-config/-/browserslist-config-1.0.0.tgz#90ca79640ffbb195a87d4d65cd4b2f92342f8b76" integrity sha512-qfKu1z9gaaHdMgRGaZBiayuIh92ishsf14lR+Rj61CJF131XWq3+5e2VyLyOdKsYJ1EreAxgyC/0upIBEzwQJw== +"@veupathdb/core-components@^0.2.46": + version "0.2.46" + resolved "https://registry.yarnpkg.com/@veupathdb/core-components/-/core-components-0.2.46.tgz#f1fc50091e49a0d7fbdb0396402d56c7847e60f0" + integrity sha512-FjQjWyrHNNMl0r3Zn9iTHeZtquvqIHvFD0mS4C40SSDeKxwZg5lIoRmIIcXcrEE/pzyZ8A4ygKa6cVnRtgzWew== + dependencies: + "@material-ui/core" "^4.12.3" + "@material-ui/icons" "^4.11.2" + lodash "^4.17.21" + react-cool-dimensions "^2.0.7" + react-modal "^3.14.3" + react-table "^7.7.0" + "@veupathdb/eslint-config@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@veupathdb/eslint-config/-/eslint-config-1.0.0.tgz#40dc855b263bd3fd68f8f61508ef55b1dc163caf" @@ -7519,6 +7631,11 @@ execa@^4.1.0: signal-exit "^3.0.2" strip-final-newline "^2.0.0" +exenv@^1.2.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d" + integrity sha1-KueOhdmJQVhnCwPUe+wfA72Ru50= + expand-brackets@^2.1.4: version "2.1.4" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" @@ -8729,7 +8846,7 @@ hmac-drbg@^1.0.0: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" -hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: +hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== @@ -9769,6 +9886,15 @@ jss-plugin-camel-case@^10.0.3: hyphenate-style-name "^1.0.3" jss "10.5.0" +jss-plugin-camel-case@^10.5.1: + version "10.8.2" + resolved "https://registry.yarnpkg.com/jss-plugin-camel-case/-/jss-plugin-camel-case-10.8.2.tgz#8d7f915c8115afaff8cbde08faf610ec9892fba6" + integrity sha512-2INyxR+1UdNuKf4v9It3tNfPvf7IPrtkiwzofeKuMd5D58/dxDJVUQYRVg/n460rTlHUfsEQx43hDrcxi9dSPA== + dependencies: + "@babel/runtime" "^7.3.1" + hyphenate-style-name "^1.0.3" + jss "10.8.2" + jss-plugin-default-unit@^10.0.3: version "10.5.0" resolved "https://registry.yarnpkg.com/jss-plugin-default-unit/-/jss-plugin-default-unit-10.5.0.tgz#e9f2e89741b0118ba15d52b4c13bda2b27262373" @@ -9777,6 +9903,14 @@ jss-plugin-default-unit@^10.0.3: "@babel/runtime" "^7.3.1" jss "10.5.0" +jss-plugin-default-unit@^10.5.1: + version "10.8.2" + resolved "https://registry.yarnpkg.com/jss-plugin-default-unit/-/jss-plugin-default-unit-10.8.2.tgz#c66f12e02e0815d911b85c02c2a979ee7b4ce69a" + integrity sha512-UZ7cwT9NFYSG+SEy7noRU50s4zifulFdjkUNKE+u6mW7vFP960+RglWjTgMfh79G6OENZmaYnjHV/gcKV4nSxg== + dependencies: + "@babel/runtime" "^7.3.1" + jss "10.8.2" + jss-plugin-global@^10.0.3: version "10.5.0" resolved "https://registry.yarnpkg.com/jss-plugin-global/-/jss-plugin-global-10.5.0.tgz#eb357ccd35cb4894277fb2117a78d1e498668ad6" @@ -9785,6 +9919,14 @@ jss-plugin-global@^10.0.3: "@babel/runtime" "^7.3.1" jss "10.5.0" +jss-plugin-global@^10.5.1: + version "10.8.2" + resolved "https://registry.yarnpkg.com/jss-plugin-global/-/jss-plugin-global-10.8.2.tgz#1a35632a693cf50113bcc5ffe6b51969df79c4ec" + integrity sha512-UaYMSPsYZ7s/ECGoj4KoHC2jwQd5iQ7K+FFGnCAILdQrv7hPmvM2Ydg45ThT/sH46DqktCRV2SqjRuxeBH8nRA== + dependencies: + "@babel/runtime" "^7.3.1" + jss "10.8.2" + jss-plugin-nested@^10.0.3: version "10.5.0" resolved "https://registry.yarnpkg.com/jss-plugin-nested/-/jss-plugin-nested-10.5.0.tgz#790c506432a23a63c71ceb5044e2ac85f0958702" @@ -9794,6 +9936,15 @@ jss-plugin-nested@^10.0.3: jss "10.5.0" tiny-warning "^1.0.2" +jss-plugin-nested@^10.5.1: + version "10.8.2" + resolved "https://registry.yarnpkg.com/jss-plugin-nested/-/jss-plugin-nested-10.8.2.tgz#79f3c7f75ea6a36ae72fe52e777035bb24d230c7" + integrity sha512-acRvuPJOb930fuYmhkJaa994EADpt8TxI63Iyg96C8FJ9T2xRyU5T6R1IYKRwUiqZo+2Sr7fdGzRTDD4uBZaMA== + dependencies: + "@babel/runtime" "^7.3.1" + jss "10.8.2" + tiny-warning "^1.0.2" + jss-plugin-props-sort@^10.0.3: version "10.5.0" resolved "https://registry.yarnpkg.com/jss-plugin-props-sort/-/jss-plugin-props-sort-10.5.0.tgz#5bcc3bd8e68cd3e2dafb47d67db28fd5a4fcf102" @@ -9802,6 +9953,14 @@ jss-plugin-props-sort@^10.0.3: "@babel/runtime" "^7.3.1" jss "10.5.0" +jss-plugin-props-sort@^10.5.1: + version "10.8.2" + resolved "https://registry.yarnpkg.com/jss-plugin-props-sort/-/jss-plugin-props-sort-10.8.2.tgz#e25a7471868652c394562b6dc5433dcaea7dff6f" + integrity sha512-wqdcjayKRWBZnNpLUrXvsWqh+5J5YToAQ+8HNBNw0kZxVvCDwzhK2Nx6AKs7p+5/MbAh2PLgNW5Ym/ysbVAuqQ== + dependencies: + "@babel/runtime" "^7.3.1" + jss "10.8.2" + jss-plugin-rule-value-function@^10.0.3: version "10.5.0" resolved "https://registry.yarnpkg.com/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.5.0.tgz#60ee8240dfe60418e1ba4729adee893cbe9be7a3" @@ -9811,6 +9970,15 @@ jss-plugin-rule-value-function@^10.0.3: jss "10.5.0" tiny-warning "^1.0.2" +jss-plugin-rule-value-function@^10.5.1: + version "10.8.2" + resolved "https://registry.yarnpkg.com/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.8.2.tgz#55354b55f1b2968a15976729968f767f02d64049" + integrity sha512-bW0EKAs+0HXpb6BKJhrn94IDdiWb0CnSluTkh0rGEgyzY/nmD1uV/Wf6KGlesGOZ9gmJzQy+9FFdxIUID1c9Ug== + dependencies: + "@babel/runtime" "^7.3.1" + jss "10.8.2" + tiny-warning "^1.0.2" + jss-plugin-vendor-prefixer@^10.0.3: version "10.5.0" resolved "https://registry.yarnpkg.com/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.5.0.tgz#01f04cfff31f43f153f5d71972f5800b10a2eb84" @@ -9820,6 +9988,15 @@ jss-plugin-vendor-prefixer@^10.0.3: css-vendor "^2.0.8" jss "10.5.0" +jss-plugin-vendor-prefixer@^10.5.1: + version "10.8.2" + resolved "https://registry.yarnpkg.com/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.8.2.tgz#ebb4a482642f34091e454901e21176441dd5f475" + integrity sha512-DeGv18QsSiYLSVIEB2+l0af6OToUe0JB+trpzUxyqD2QRC/5AzzDrCrYffO5AHZ81QbffYvSN/pkfZaTWpRXlg== + dependencies: + "@babel/runtime" "^7.3.1" + css-vendor "^2.0.8" + jss "10.8.2" + jss@10.5.0, jss@^10.0.3: version "10.5.0" resolved "https://registry.yarnpkg.com/jss/-/jss-10.5.0.tgz#0c2de8a29874b2dc8162ab7f34ef6573a87d9dd3" @@ -9831,6 +10008,16 @@ jss@10.5.0, jss@^10.0.3: is-in-browser "^1.1.3" tiny-warning "^1.0.2" +jss@10.8.2, jss@^10.5.1: + version "10.8.2" + resolved "https://registry.yarnpkg.com/jss/-/jss-10.8.2.tgz#4b2a30b094b924629a64928236017a52c7c97505" + integrity sha512-FkoUNxI329CKQ9OQC8L72MBF9KPf5q8mIupAJ5twU7G7XREW7ahb+7jFfrjZ4iy1qvhx1HwIWUIvkZBDnKkEdQ== + dependencies: + "@babel/runtime" "^7.3.1" + csstype "^3.0.2" + is-in-browser "^1.1.3" + tiny-warning "^1.0.2" + junk@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/junk/-/junk-3.1.0.tgz#31499098d902b7e98c5d9b9c80f43457a88abfa1" @@ -11962,6 +12149,11 @@ react-cool-dimensions@^1.1.11: resolved "https://registry.yarnpkg.com/react-cool-dimensions/-/react-cool-dimensions-1.1.11.tgz#645b20a74e9462ed192f29f1cd43805dd29ccf26" integrity sha512-x6nEAVhbiojN6nPiCA04L8LY494uqA3+5E/0lIxQ20UzLKr3ttcuETgOygH2PVKMiaCfhQ0BabmDa30sYgzIeA== +react-cool-dimensions@^2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/react-cool-dimensions/-/react-cool-dimensions-2.0.7.tgz#2fe6657608f034cd7c89f149ed14e79cf1cb2d50" + integrity sha512-z1VwkAAJ5d8QybDRuYIXTE41RxGr5GYsv1bQhbOBE8cMfoZQZpcF0odL64vdgrQVzat2jayedj1GoYi80FWcbA== + react-dev-utils@^11.0.3: version "11.0.3" resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-11.0.3.tgz#b61ed499c7d74f447d4faddcc547e5e671e97c08" @@ -12106,11 +12298,21 @@ react-leaflet@^2.7.0: hoist-non-react-statics "^3.3.2" warning "^4.0.3" -react-lifecycles-compat@^3.0.4: +react-lifecycles-compat@^3.0.0, react-lifecycles-compat@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== +react-modal@^3.14.3: + version "3.14.4" + resolved "https://registry.yarnpkg.com/react-modal/-/react-modal-3.14.4.tgz#2ca7e8e9a180955e5c9508c228b73167c1e6f6a3" + integrity sha512-8surmulejafYCH9wfUmFyj4UfbSJwjcgbS9gf3oOItu4Hwd6ivJyVBETI0yHRhpJKCLZMUtnhzk76wXTsNL6Qg== + dependencies: + exenv "^1.2.0" + prop-types "^15.7.2" + react-lifecycles-compat "^3.0.0" + warning "^4.0.3" + react-overlays@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/react-overlays/-/react-overlays-4.1.1.tgz#0060107cbe1c5171a744ccda3fbf0556d064bc5f" @@ -12189,6 +12391,11 @@ react-syntax-highlighter@^13.5.3: prismjs "^1.21.0" refractor "^3.1.0" +react-table@^7.7.0: + version "7.7.0" + resolved "https://registry.yarnpkg.com/react-table/-/react-table-7.7.0.tgz#e2ce14d7fe3a559f7444e9ecfe8231ea8373f912" + integrity sha512-jBlj70iBwOTvvImsU9t01LjFjy4sXEtclBovl3mTiqjz23Reu0DKnRza4zlLtOPACx6j2/7MrQIthIK1Wi+LIA== + react-textarea-autosize@^8.3.0: version "8.3.3" resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-8.3.3.tgz#f70913945369da453fd554c168f6baacd1fa04d8" @@ -13560,6 +13767,11 @@ style-to-object@0.3.0, style-to-object@^0.3.0: dependencies: inline-style-parser "0.1.1" +stylis@^4.0.10: + version "4.0.10" + resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.0.10.tgz#446512d1097197ab3f02fb3c258358c3f7a14240" + integrity sha512-m3k+dk7QeJw660eIKRRn3xPF6uuvHs/FFzjX3HQ5ove0qYsiygoAhwn5a3IYKaZPo5LrYD0rfVmtv1gNY1uYwg== + supercluster@^7.0.0: version "7.1.0" resolved "https://registry.yarnpkg.com/supercluster/-/supercluster-7.1.0.tgz#f0a457426ec0ab95d69c5f03b51e049774b94479"