Skip to content

Commit

Permalink
[charts] Make typescript more flexible about plugins and their params (
Browse files Browse the repository at this point in the history
…#16478)

Co-authored-by: Jose Quintas <[email protected]>
  • Loading branch information
alexfauquette and JCQuintas authored Feb 7, 2025
1 parent 7805988 commit d8f2691
Show file tree
Hide file tree
Showing 24 changed files with 340 additions and 435 deletions.
76 changes: 8 additions & 68 deletions docs/pages/x/api/charts/chart-data-provider-pro.json
Original file line number Diff line number Diff line change
@@ -1,73 +1,13 @@
{
"props": {
"colors": {
"type": { "name": "union", "description": "Array&lt;string&gt;<br>&#124;&nbsp;func" },
"default": "rainbowSurgePalette"
},
"dataset": { "type": { "name": "arrayOf", "description": "Array&lt;object&gt;" } },
"disableAxisListener": { "type": { "name": "bool" }, "default": "false" },
"height": { "type": { "name": "number" } },
"highlightedItem": {
"type": {
"name": "shape",
"description": "{ dataIndex?: number, seriesId: number<br>&#124;&nbsp;string }"
}
},
"id": { "type": { "name": "string" } },
"initialZoom": {
"type": {
"name": "arrayOf",
"description": "Array&lt;{ axisId: number<br>&#124;&nbsp;string, end: number, start: number }&gt;"
}
},
"margin": {
"type": {
"name": "shape",
"description": "{ bottom?: number, left?: number, right?: number, top?: number }"
}
},
"onAxisClick": {
"type": { "name": "func" },
"signature": {
"type": "function(event: MouseEvent, data: null | AxisData) => void",
"describedArgs": ["event", "data"]
}
},
"onHighlightChange": {
"type": { "name": "func" },
"signature": {
"type": "function(highlightedItem: HighlightItemData | null) => void",
"describedArgs": ["highlightedItem"]
}
},
"onZoomChange": {
"type": { "name": "func" },
"signature": {
"type": "function(zoomData: Array<ZoomData>) => void",
"describedArgs": ["zoomData"]
}
},
"series": { "type": { "name": "arrayOf", "description": "Array&lt;object&gt;" } },
"skipAnimation": { "type": { "name": "bool" } },
"width": { "type": { "name": "number" } },
"xAxis": {
"type": {
"name": "arrayOf",
"description": "Array&lt;{ classes?: object, colorMap?: { colors: Array&lt;string&gt;, type: 'ordinal', unknownColor?: string, values?: Array&lt;Date<br>&#124;&nbsp;number<br>&#124;&nbsp;string&gt; }<br>&#124;&nbsp;{ color: Array&lt;string&gt;<br>&#124;&nbsp;func, max?: Date<br>&#124;&nbsp;number, min?: Date<br>&#124;&nbsp;number, type: 'continuous' }<br>&#124;&nbsp;{ colors: Array&lt;string&gt;, thresholds: Array&lt;Date<br>&#124;&nbsp;number&gt;, type: 'piecewise' }, data?: array, dataKey?: string, disableLine?: bool, disableTicks?: bool, domainLimit?: 'nice'<br>&#124;&nbsp;'strict'<br>&#124;&nbsp;func, fill?: string, hideTooltip?: bool, id?: number<br>&#124;&nbsp;string, label?: string, labelStyle?: object, max?: Date<br>&#124;&nbsp;number, min?: Date<br>&#124;&nbsp;number, position?: 'bottom'<br>&#124;&nbsp;'top', reverse?: bool, scaleType?: 'band'<br>&#124;&nbsp;'linear'<br>&#124;&nbsp;'log'<br>&#124;&nbsp;'point'<br>&#124;&nbsp;'pow'<br>&#124;&nbsp;'sqrt'<br>&#124;&nbsp;'time'<br>&#124;&nbsp;'utc', slotProps?: object, slots?: object, stroke?: string, sx?: Array&lt;func<br>&#124;&nbsp;object<br>&#124;&nbsp;bool&gt;<br>&#124;&nbsp;func<br>&#124;&nbsp;object, tickInterval?: 'auto'<br>&#124;&nbsp;array<br>&#124;&nbsp;func, tickLabelInterval?: 'auto'<br>&#124;&nbsp;func, tickLabelPlacement?: 'middle'<br>&#124;&nbsp;'tick', tickLabelStyle?: object, tickMaxStep?: number, tickMinStep?: number, tickNumber?: number, tickPlacement?: 'end'<br>&#124;&nbsp;'extremities'<br>&#124;&nbsp;'middle'<br>&#124;&nbsp;'start', tickSize?: number, valueFormatter?: func, zoom?: { filterMode?: 'discard'<br>&#124;&nbsp;'keep', maxEnd?: number, maxSpan?: number, minSpan?: number, minStart?: number, panning?: bool, step?: number }<br>&#124;&nbsp;bool }&gt;"
}
},
"yAxis": {
"type": {
"name": "arrayOf",
"description": "Array&lt;{ classes?: object, colorMap?: { colors: Array&lt;string&gt;, type: 'ordinal', unknownColor?: string, values?: Array&lt;Date<br>&#124;&nbsp;number<br>&#124;&nbsp;string&gt; }<br>&#124;&nbsp;{ color: Array&lt;string&gt;<br>&#124;&nbsp;func, max?: Date<br>&#124;&nbsp;number, min?: Date<br>&#124;&nbsp;number, type: 'continuous' }<br>&#124;&nbsp;{ colors: Array&lt;string&gt;, thresholds: Array&lt;Date<br>&#124;&nbsp;number&gt;, type: 'piecewise' }, data?: array, dataKey?: string, disableLine?: bool, disableTicks?: bool, domainLimit?: 'nice'<br>&#124;&nbsp;'strict'<br>&#124;&nbsp;func, fill?: string, hideTooltip?: bool, id?: number<br>&#124;&nbsp;string, label?: string, labelStyle?: object, max?: Date<br>&#124;&nbsp;number, min?: Date<br>&#124;&nbsp;number, position?: 'left'<br>&#124;&nbsp;'right', reverse?: bool, scaleType?: 'band'<br>&#124;&nbsp;'linear'<br>&#124;&nbsp;'log'<br>&#124;&nbsp;'point'<br>&#124;&nbsp;'pow'<br>&#124;&nbsp;'sqrt'<br>&#124;&nbsp;'time'<br>&#124;&nbsp;'utc', slotProps?: object, slots?: object, stroke?: string, sx?: Array&lt;func<br>&#124;&nbsp;object<br>&#124;&nbsp;bool&gt;<br>&#124;&nbsp;func<br>&#124;&nbsp;object, tickInterval?: 'auto'<br>&#124;&nbsp;array<br>&#124;&nbsp;func, tickLabelInterval?: 'auto'<br>&#124;&nbsp;func, tickLabelPlacement?: 'middle'<br>&#124;&nbsp;'tick', tickLabelStyle?: object, tickMaxStep?: number, tickMinStep?: number, tickNumber?: number, tickPlacement?: 'end'<br>&#124;&nbsp;'extremities'<br>&#124;&nbsp;'middle'<br>&#124;&nbsp;'start', tickSize?: number, valueFormatter?: func, zoom?: { filterMode?: 'discard'<br>&#124;&nbsp;'keep', maxEnd?: number, maxSpan?: number, minSpan?: number, minStart?: number, panning?: bool, step?: number }<br>&#124;&nbsp;bool }&gt;"
}
},
"zAxis": {
"type": {
"name": "arrayOf",
"description": "Array&lt;{ colorMap?: { colors: Array&lt;string&gt;, type: 'ordinal', unknownColor?: string, values?: Array&lt;Date<br>&#124;&nbsp;number<br>&#124;&nbsp;string&gt; }<br>&#124;&nbsp;{ color: Array&lt;string&gt;<br>&#124;&nbsp;func, max?: Date<br>&#124;&nbsp;number, min?: Date<br>&#124;&nbsp;number, type: 'continuous' }<br>&#124;&nbsp;{ colors: Array&lt;string&gt;, thresholds: Array&lt;Date<br>&#124;&nbsp;number&gt;, type: 'piecewise' }, data?: array, dataKey?: string, id?: string, max?: number, min?: number }&gt;"
}
}
"colors": { "type": { "name": "any" }, "default": "rainbowSurgePalette" },
"dataset": { "type": { "name": "any" } },
"height": { "type": { "name": "any" } },
"id": { "type": { "name": "any" } },
"margin": { "type": { "name": "any" } },
"series": { "type": { "name": "any" } },
"skipAnimation": { "type": { "name": "any" } },
"width": { "type": { "name": "any" } }
},
"name": "ChartDataProviderPro",
"imports": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,37 +5,15 @@
"dataset": {
"description": "An array of objects that can be used to populate series and axes data using their <code>dataKey</code> property."
},
"disableAxisListener": {
"description": "If <code>true</code>, the charts will not listen to the mouse move event. It might break interactive features, but will improve performance."
},
"height": {
"description": "The height of the chart in px. If not defined, it takes the height of the parent element."
},
"highlightedItem": {
"description": "The highlighted item. Used when the highlight is controlled."
},
"id": {
"description": "This prop is used to help implement the accessibility logic. If you don&#39;t provide this prop. It falls back to a randomly generated id."
},
"initialZoom": { "description": "The list of zoom data related to each axis." },
"margin": {
"description": "The margin between the SVG and the drawing area. It&#39;s used for leaving some space for extra information such as the x- and y-axis or legend. Accepts an object with the optional properties: <code>top</code>, <code>bottom</code>, <code>left</code>, and <code>right</code>."
},
"onAxisClick": {
"description": "The function called for onClick events. The second argument contains information about all line/bar elements at the current mouse position.",
"typeDescriptions": {
"event": "The mouse event recorded on the <code>&lt;svg/&gt;</code> element.",
"data": "The data about the clicked axis and items associated with it."
}
},
"onHighlightChange": {
"description": "The callback fired when the highlighted item changes.",
"typeDescriptions": { "highlightedItem": "The newly highlighted item." }
},
"onZoomChange": {
"description": "Callback fired when the zoom has changed.",
"typeDescriptions": { "zoomData": "Updated zoom data." }
},
"series": {
"description": "The array of series to display. Each type of series has its own specificity. Please refer to the appropriate docs page to learn more about it."
},
Expand All @@ -44,14 +22,7 @@
},
"width": {
"description": "The width of the chart in px. If not defined, it takes the width of the parent element."
},
"xAxis": {
"description": "The configuration of the x-axes. If not provided, a default axis config is used. An array of <a href='/x/api/charts/axis-config/'>AxisConfig</a> objects."
},
"yAxis": {
"description": "The configuration of the y-axes. If not provided, a default axis config is used. An array of <a href='/x/api/charts/axis-config/'>AxisConfig</a> objects."
},
"zAxis": { "description": "The configuration of the z-axes." }
}
},
"classDescriptions": {}
}
28 changes: 28 additions & 0 deletions packages/x-charts-pro/src/BarChartPro/BarChartPro.plugins.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import {
useChartZAxis,
UseChartZAxisSignature,
useChartCartesianAxis,
UseChartCartesianAxisSignature,
useChartInteraction,
UseChartInteractionSignature,
useChartHighlight,
UseChartHighlightSignature,
ConvertSignaturesIntoPlugins,
} from '@mui/x-charts/internals';
import { useChartProZoom, UseChartProZoomSignature } from '../internals/plugins/useChartProZoom';

export type BarChartProPluginsSignatures = [
UseChartZAxisSignature,
UseChartCartesianAxisSignature<'bar'>,
UseChartInteractionSignature,
UseChartHighlightSignature,
UseChartProZoomSignature,
];

export const BAR_CHART_PRO_PLUGINS: ConvertSignaturesIntoPlugins<BarChartProPluginsSignatures> = [
useChartZAxis,
useChartCartesianAxis,
useChartInteraction,
useChartHighlight,
useChartProZoom,
];
8 changes: 6 additions & 2 deletions packages/x-charts-pro/src/BarChartPro/BarChartPro.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { ChartContainerProProps } from '../ChartContainerPro';
import { useIsZoomInteracting } from '../hooks/zoom';
import { useChartContainerProProps } from '../ChartContainerPro/useChartContainerProProps';
import { ChartDataProviderPro } from '../ChartDataProviderPro';
import { BAR_CHART_PRO_PLUGINS, BarChartProPluginsSignatures } from './BarChartPro.plugins';

function BarChartPlotZoom(props: BarPlotProps) {
const isInteracting = useIsZoomInteracting();
Expand Down Expand Up @@ -98,8 +99,11 @@ const BarChartPro = React.forwardRef(function BarChartPro(
children,
} = useBarChartProps(other);

const { chartDataProviderProProps, chartsSurfaceProps } = useChartContainerProProps(
{ ...chartContainerProps, initialZoom, onZoomChange, apiRef },
const { chartDataProviderProProps, chartsSurfaceProps } = useChartContainerProProps<
'bar',
BarChartProPluginsSignatures
>(
{ ...chartContainerProps, initialZoom, onZoomChange, apiRef, plugins: BAR_CHART_PRO_PLUGINS },
ref,
);

Expand Down
25 changes: 16 additions & 9 deletions packages/x-charts-pro/src/ChartContainerPro/ChartContainerPro.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,21 @@ import * as React from 'react';
import PropTypes from 'prop-types';
import type {} from '../typeOverloads';
import { ChartsSurface, ChartsSurfaceProps } from '@mui/x-charts/ChartsSurface';
import { ChartSeriesType } from '@mui/x-charts/internals';
import { ChartAnyPluginSignature, ChartSeriesType } from '@mui/x-charts/internals';
import { useChartContainerProProps } from './useChartContainerProProps';
import { AllPluginSignatures } from '../internals/plugins/allPlugins';
import { ChartDataProviderPro, ChartDataProviderProProps } from '../ChartDataProviderPro';

export interface ChartContainerProProps<TSeries extends ChartSeriesType = ChartSeriesType>
extends ChartDataProviderProProps<TSeries, AllPluginSignatures<TSeries>>,
ChartsSurfaceProps {}
export type ChartContainerProProps<
TSeries extends ChartSeriesType = ChartSeriesType,
TSignatures extends readonly ChartAnyPluginSignature[] = AllPluginSignatures<TSeries>,
> = ChartDataProviderProProps<TSeries, TSignatures> & ChartsSurfaceProps;

type ChartContainerProComponent = <TSeries extends ChartSeriesType = ChartSeriesType>(
props: ChartContainerProProps<TSeries> & { ref?: React.ForwardedRef<SVGSVGElement> },
type ChartContainerProComponent = <
TSeries extends ChartSeriesType = ChartSeriesType,
TSignatures extends readonly ChartAnyPluginSignature[] = AllPluginSignatures<TSeries>,
>(
props: ChartContainerProProps<TSeries, TSignatures> & { ref?: React.ForwardedRef<SVGSVGElement> },
) => React.JSX.Element;

/**
Expand Down Expand Up @@ -42,9 +46,12 @@ type ChartContainerProComponent = <TSeries extends ChartSeriesType = ChartSeries
*/
const ChartContainerPro = React.forwardRef(function ChartContainerProInner<
TSeries extends ChartSeriesType = ChartSeriesType,
>(props: ChartContainerProProps<TSeries>, ref: React.Ref<SVGSVGElement>) {
const { chartDataProviderProProps, children, chartsSurfaceProps } =
useChartContainerProProps<TSeries>(props, ref);
TSignatures extends readonly ChartAnyPluginSignature[] = AllPluginSignatures<TSeries>,
>(props: ChartContainerProProps<TSeries, TSignatures>, ref: React.Ref<SVGSVGElement>) {
const { chartDataProviderProProps, children, chartsSurfaceProps } = useChartContainerProProps<
TSeries,
TSignatures
>(props, ref);

return (
<ChartDataProviderPro {...chartDataProviderProProps}>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,47 +1,50 @@
'use client';
import {
ChartAnyPluginSignature,
ChartSeriesType,
useChartContainerProps,
UseChartContainerPropsReturnValue,
} from '@mui/x-charts/internals';
import * as React from 'react';
import { ChartDataProviderProps } from '@mui/x-charts/ChartDataProvider';
import type { ChartContainerProProps } from './ChartContainerPro';
import { ALL_PLUGINS, AllPluginsType, AllPluginSignatures } from '../internals/plugins/allPlugins';
import { ALL_PLUGINS, AllPluginSignatures } from '../internals/plugins/allPlugins';

export type UseChartContainerProPropsReturnValue<TSeries extends ChartSeriesType> = Pick<
UseChartContainerPropsReturnValue<TSeries>,
export type UseChartContainerProPropsReturnValue<
TSeries extends ChartSeriesType,
TSignatures extends readonly ChartAnyPluginSignature[],
> = Pick<
UseChartContainerPropsReturnValue<TSeries, TSignatures>,
'chartsSurfaceProps' | 'children'
> & {
chartDataProviderProProps: ChartDataProviderProps<TSeries, AllPluginSignatures<TSeries>>;
chartDataProviderProProps: ChartDataProviderProps<TSeries, TSignatures>;
};

export const useChartContainerProProps = <TSeries extends ChartSeriesType = ChartSeriesType>(
props: ChartContainerProProps<TSeries>,
export const useChartContainerProProps = <
TSeries extends ChartSeriesType = ChartSeriesType,
TSignatures extends readonly ChartAnyPluginSignature[] = AllPluginSignatures<TSeries>,
>(
props: ChartContainerProProps<TSeries, TSignatures>,
ref: React.Ref<SVGSVGElement>,
): UseChartContainerProPropsReturnValue<TSeries> => {
const { initialZoom, onZoomChange, plugins, apiRef, ...baseProps } = props;

const chartDataProviderProProps: Pick<
ChartDataProviderProps<TSeries, AllPluginSignatures<TSeries>>,
'initialZoom' | 'onZoomChange'
> = {
initialZoom,
onZoomChange,
};
): UseChartContainerProPropsReturnValue<TSeries, TSignatures> => {
const { initialZoom, onZoomChange, plugins, apiRef, ...baseProps } =
props as ChartContainerProProps<TSeries, AllPluginSignatures>;

const { chartDataProviderProps, chartsSurfaceProps, children } = useChartContainerProps<TSeries>(
baseProps,
ref,
);

const chartDataProviderProProps = {
...chartDataProviderProps,
initialZoom,
onZoomChange,
apiRef,
plugins: plugins ?? ALL_PLUGINS,
} as unknown as ChartDataProviderProps<TSeries, TSignatures>;

return {
chartDataProviderProProps: {
...chartDataProviderProps,
...chartDataProviderProProps,
apiRef,
plugins: plugins ?? (ALL_PLUGINS as unknown as AllPluginsType<TSeries>),
},
chartDataProviderProProps,
chartsSurfaceProps,
children,
};
Expand Down
Loading

0 comments on commit d8f2691

Please sign in to comment.