diff --git a/docs/data/data-grid/master-detail/master-detail.md b/docs/data/data-grid/master-detail/master-detail.md
index 679a57852f15..0af556b2bd03 100644
--- a/docs/data/data-grid/master-detail/master-detail.md
+++ b/docs/data/data-grid/master-detail/master-detail.md
@@ -135,6 +135,31 @@ This approach can also be used to change the location of the toggle column, as s
As any ordinary cell renderer, the `value` prop is also available, and it corresponds to the state of the row: `true` when expanded and `false` when collapsed.
:::
+## Custom header for detail panel column
+
+To render a custom header for the detail panel column, use the [`renderHeader`](/x/react-data-grid/column-header/#custom-header-renderer) property in the column definition.
+This property receives a `GridRenderHeaderParams` object that contains `colDef` (the column definition) and `field`.
+The following example demonstrates how to render a custom header for the detail panel column:
+
+```tsx
+const columns = [
+ {
+ ...GRID_DETAIL_PANEL_TOGGLE_COL_DEF,
+ renderHeader: (params) => (
+
+ {params.colDef.headerName}
+ console.log('Custom action')}>Custom action
+
+ ),
+ },
+ //... other columns
+];
+```
+
+:::info
+For a more advanced example check out the [Expand or collapse all detail panels](/x/react-data-grid/row-recipes/#expand-or-collapse-all-detail-panels) recipe.
+:::
+
## Disable detail panel content scroll
By default, the detail panel has a width that is the sum of the widths of all columns.
@@ -153,6 +178,7 @@ Notice that the toggle column is pinned to make sure that it will always be visi
More examples of how to customize the detail panel:
- [One expanded detail panel at a time](/x/react-data-grid/row-recipes/#one-expanded-detail-panel-at-a-time)
+- [Expand or collapse all detail panels](/x/react-data-grid/row-recipes/#expand-or-collapse-all-detail-panels)
## apiRef
diff --git a/docs/data/data-grid/row-recipes/DetailPanelCollapseAll.tsx.preview b/docs/data/data-grid/row-recipes/DetailPanelCollapseAll.tsx.preview
new file mode 100644
index 000000000000..d89161b50e8d
--- /dev/null
+++ b/docs/data/data-grid/row-recipes/DetailPanelCollapseAll.tsx.preview
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/docs/data/data-grid/row-recipes/DetailPanelExpandCollapseAll.js b/docs/data/data-grid/row-recipes/DetailPanelExpandCollapseAll.js
new file mode 100644
index 000000000000..cd48306cf1ba
--- /dev/null
+++ b/docs/data/data-grid/row-recipes/DetailPanelExpandCollapseAll.js
@@ -0,0 +1,134 @@
+import * as React from 'react';
+import Box from '@mui/material/Box';
+import IconButton from '@mui/material/IconButton';
+import UnfoldLessIcon from '@mui/icons-material/UnfoldLess';
+import UnfoldMoreIcon from '@mui/icons-material/UnfoldMore';
+import {
+ DataGridPro,
+ useGridApiContext,
+ useGridSelector,
+ gridRowsLookupSelector,
+ gridDetailPanelExpandedRowIdsSelector,
+ gridDetailPanelExpandedRowsContentCacheSelector,
+ GRID_DETAIL_PANEL_TOGGLE_COL_DEF,
+} from '@mui/x-data-grid-pro';
+import {
+ randomCreatedDate,
+ randomCurrency,
+ randomEmail,
+ randomPrice,
+} from '@mui/x-data-grid-generator';
+
+export default function DetailPanelExpandCollapseAll() {
+ const getDetailPanelContent = React.useCallback(
+ ({ row }) => {`Order #${row.id}`} ,
+ [],
+ );
+
+ const getDetailPanelHeight = React.useCallback(() => 50, []);
+
+ return (
+
+
+
+ );
+}
+
+function CustomDetailPanelHeader() {
+ const apiRef = useGridApiContext();
+
+ const expandedRowIds = useGridSelector(
+ apiRef,
+ gridDetailPanelExpandedRowIdsSelector,
+ );
+ const rowsWithDetailPanels = useGridSelector(
+ apiRef,
+ gridDetailPanelExpandedRowsContentCacheSelector,
+ );
+
+ const noDetailPanelsOpen = expandedRowIds.length === 0;
+
+ const expandOrCollapseAll = () => {
+ const dataRowIdToModelLookup = gridRowsLookupSelector(apiRef);
+ const allRowIdsWithDetailPanels = Object.keys(rowsWithDetailPanels).map((key) =>
+ apiRef.current.getRowId(dataRowIdToModelLookup[key]),
+ );
+
+ apiRef.current.setExpandedDetailPanels(
+ noDetailPanelsOpen ? allRowIdsWithDetailPanels : [],
+ );
+ };
+
+ const Icon = noDetailPanelsOpen ? UnfoldMoreIcon : UnfoldLessIcon;
+
+ return (
+
+
+
+ );
+}
+
+const columns = [
+ {
+ ...GRID_DETAIL_PANEL_TOGGLE_COL_DEF,
+ renderHeader: () => ,
+ },
+ { field: 'id', headerName: 'Order ID' },
+ { field: 'customer', headerName: 'Customer', width: 200 },
+ { field: 'date', type: 'date', headerName: 'Placed at' },
+ { field: 'currency', headerName: 'Currency' },
+ { field: 'total', type: 'number', headerName: 'Total' },
+];
+
+const rows = [
+ {
+ id: 1,
+ customer: 'Matheus',
+ email: randomEmail(),
+ date: randomCreatedDate(),
+ currency: randomCurrency(),
+ total: randomPrice(1, 1000),
+ },
+ {
+ id: 2,
+ customer: 'Olivier',
+ email: randomEmail(),
+ date: randomCreatedDate(),
+ currency: randomCurrency(),
+ total: randomPrice(1, 1000),
+ },
+ {
+ id: 3,
+ customer: 'Flavien',
+ email: randomEmail(),
+ date: randomCreatedDate(),
+ currency: randomCurrency(),
+ total: randomPrice(1, 1000),
+ },
+ {
+ id: 4,
+ customer: 'Danail',
+ email: randomEmail(),
+ date: randomCreatedDate(),
+ currency: randomCurrency(),
+ total: randomPrice(1, 1000),
+ },
+ {
+ id: 5,
+ customer: 'Alexandre',
+ email: randomEmail(),
+ date: randomCreatedDate(),
+ currency: randomCurrency(),
+ total: randomPrice(1, 1000),
+ },
+];
diff --git a/docs/data/data-grid/row-recipes/DetailPanelExpandCollapseAll.tsx b/docs/data/data-grid/row-recipes/DetailPanelExpandCollapseAll.tsx
new file mode 100644
index 000000000000..a85385042f8c
--- /dev/null
+++ b/docs/data/data-grid/row-recipes/DetailPanelExpandCollapseAll.tsx
@@ -0,0 +1,138 @@
+import * as React from 'react';
+import Box from '@mui/material/Box';
+import IconButton from '@mui/material/IconButton';
+import UnfoldLessIcon from '@mui/icons-material/UnfoldLess';
+import UnfoldMoreIcon from '@mui/icons-material/UnfoldMore';
+import {
+ DataGridPro,
+ GridColDef,
+ GridRowsProp,
+ GridRowParams,
+ useGridApiContext,
+ useGridSelector,
+ gridRowsLookupSelector,
+ gridDetailPanelExpandedRowIdsSelector,
+ gridDetailPanelExpandedRowsContentCacheSelector,
+ GRID_DETAIL_PANEL_TOGGLE_COL_DEF,
+ GridRowId,
+} from '@mui/x-data-grid-pro';
+import {
+ randomCreatedDate,
+ randomCurrency,
+ randomEmail,
+ randomPrice,
+} from '@mui/x-data-grid-generator';
+
+export default function DetailPanelExpandCollapseAll() {
+ const getDetailPanelContent = React.useCallback(
+ ({ row }: GridRowParams) => {`Order #${row.id}`} ,
+ [],
+ );
+
+ const getDetailPanelHeight = React.useCallback(() => 50, []);
+
+ return (
+
+
+
+ );
+}
+
+function CustomDetailPanelHeader() {
+ const apiRef = useGridApiContext();
+
+ const expandedRowIds = useGridSelector(
+ apiRef,
+ gridDetailPanelExpandedRowIdsSelector,
+ );
+ const rowsWithDetailPanels = useGridSelector(
+ apiRef,
+ gridDetailPanelExpandedRowsContentCacheSelector,
+ );
+
+ const noDetailPanelsOpen = expandedRowIds.length === 0;
+
+ const expandOrCollapseAll = () => {
+ const dataRowIdToModelLookup = gridRowsLookupSelector(apiRef);
+ const allRowIdsWithDetailPanels: GridRowId[] = Object.keys(
+ rowsWithDetailPanels,
+ ).map((key) => apiRef.current.getRowId(dataRowIdToModelLookup[key]));
+
+ apiRef.current.setExpandedDetailPanels(
+ noDetailPanelsOpen ? allRowIdsWithDetailPanels : [],
+ );
+ };
+
+ const Icon = noDetailPanelsOpen ? UnfoldMoreIcon : UnfoldLessIcon;
+
+ return (
+
+
+
+ );
+}
+
+const columns: GridColDef[] = [
+ {
+ ...GRID_DETAIL_PANEL_TOGGLE_COL_DEF,
+ renderHeader: () => ,
+ },
+ { field: 'id', headerName: 'Order ID' },
+ { field: 'customer', headerName: 'Customer', width: 200 },
+ { field: 'date', type: 'date', headerName: 'Placed at' },
+ { field: 'currency', headerName: 'Currency' },
+ { field: 'total', type: 'number', headerName: 'Total' },
+];
+
+const rows: GridRowsProp = [
+ {
+ id: 1,
+ customer: 'Matheus',
+ email: randomEmail(),
+ date: randomCreatedDate(),
+ currency: randomCurrency(),
+ total: randomPrice(1, 1000),
+ },
+ {
+ id: 2,
+ customer: 'Olivier',
+ email: randomEmail(),
+ date: randomCreatedDate(),
+ currency: randomCurrency(),
+ total: randomPrice(1, 1000),
+ },
+ {
+ id: 3,
+ customer: 'Flavien',
+ email: randomEmail(),
+ date: randomCreatedDate(),
+ currency: randomCurrency(),
+ total: randomPrice(1, 1000),
+ },
+ {
+ id: 4,
+ customer: 'Danail',
+ email: randomEmail(),
+ date: randomCreatedDate(),
+ currency: randomCurrency(),
+ total: randomPrice(1, 1000),
+ },
+ {
+ id: 5,
+ customer: 'Alexandre',
+ email: randomEmail(),
+ date: randomCreatedDate(),
+ currency: randomCurrency(),
+ total: randomPrice(1, 1000),
+ },
+];
diff --git a/docs/data/data-grid/row-recipes/DetailPanelExpandCollapseAll.tsx.preview b/docs/data/data-grid/row-recipes/DetailPanelExpandCollapseAll.tsx.preview
new file mode 100644
index 000000000000..d89161b50e8d
--- /dev/null
+++ b/docs/data/data-grid/row-recipes/DetailPanelExpandCollapseAll.tsx.preview
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/docs/data/data-grid/row-recipes/row-recipes.md b/docs/data/data-grid/row-recipes/row-recipes.md
index b032a14754a4..6404572a316c 100644
--- a/docs/data/data-grid/row-recipes/row-recipes.md
+++ b/docs/data/data-grid/row-recipes/row-recipes.md
@@ -13,3 +13,15 @@ By default, the [Master detail ](/x/react-data-grid/mas
However, you can [control the expanded detail panels](/x/react-data-grid/master-detail/#controlling-expanded-detail-panels) to have only one detail panel expanded at a time.
{{"demo": "DetailPanelOneExpandedRow.js", "bg": "inline", "defaultCodeOpen": false}}
+
+## Expand or collapse all detail panels
+
+The following demo shows how to create a custom header element that expands or collapses all detail panels at once.
+
+Here's how it works:
+
+The custom header uses `gridRowsLookupSelector` to find all rows with a detail panel.
+It checks the status of open panels using the [`useGridSelector` hook](/x/react-data-grid/state/#with-usegridselector) to access the grid's state.
+When clicked, it uses [`setExpandedDetailPanels`](/x/api/data-grid/grid-api/#grid-api-prop-setExpandedDetailPanels) from the [Grid API](/x/react-data-grid/api-object/#how-to-use-the-api-object) to expand or collapse all detail panels.
+
+{{"demo": "DetailPanelExpandCollapseAll.js", "bg": "inline", "defaultCodeOpen": false}}
diff --git a/docs/data/tree-view/rich-tree-view/headless/LogExpandedItems.tsx b/docs/data/tree-view/rich-tree-view/headless/LogExpandedItems.tsx
index 75c05b7c6b9a..c1a70f335c0e 100644
--- a/docs/data/tree-view/rich-tree-view/headless/LogExpandedItems.tsx
+++ b/docs/data/tree-view/rich-tree-view/headless/LogExpandedItems.tsx
@@ -21,6 +21,7 @@ import {
extractPluginParamsFromProps,
useTreeView,
TreeViewProvider,
+ ConvertPluginsIntoSignatures,
} from '@mui/x-tree-view/internals';
interface TreeViewLogExpandedParameters {
@@ -88,7 +89,7 @@ function TreeView(
const ownerState = themeProps as TreeViewProps;
const { pluginParams, otherProps } = extractPluginParamsFromProps<
- typeof TREE_VIEW_PLUGINS,
+ ConvertPluginsIntoSignatures,
DefaultTreeViewPluginSlots,
DefaultTreeViewPluginSlotProps,
TreeViewProps
diff --git a/docs/data/tree-view/rich-tree-view/headless/headless.md b/docs/data/tree-view/rich-tree-view/headless/headless.md
index 99955f996285..86ca7bfccbc5 100644
--- a/docs/data/tree-view/rich-tree-view/headless/headless.md
+++ b/docs/data/tree-view/rich-tree-view/headless/headless.md
@@ -237,7 +237,7 @@ function useTreeItemState(itemId: string) {
const {
customPlugin,
// ...other elements returned by the context
- } = useTreeViewContext();
+ } = useTreeViewContext();
// ...rest of the `useTreeItemState` hook content
diff --git a/packages/x-charts/src/ChartContainer/ChartContainer.tsx b/packages/x-charts/src/ChartContainer/ChartContainer.tsx
index 812368b60a87..31770a088e55 100644
--- a/packages/x-charts/src/ChartContainer/ChartContainer.tsx
+++ b/packages/x-charts/src/ChartContainer/ChartContainer.tsx
@@ -7,6 +7,7 @@ import {
SeriesContextProviderProps,
} from '../context/SeriesContextProvider';
import { InteractionProvider } from '../context/InteractionProvider';
+import { ColorProvider } from '../context/ColorProvider';
import { useReducedMotion } from '../hooks/useReducedMotion';
import { ChartsSurface, ChartsSurfaceProps } from '../ChartsSurface';
import {
@@ -57,39 +58,48 @@ const ChartContainer = React.forwardRef(function ChartContainer(props: ChartCont
const svgRef = React.useRef(null);
const handleRef = useForkRef(ref, svgRef);
- const { seriesFormatters } = usePluginsMerge(plugins);
+ const { xExtremumGetters, yExtremumGetters, seriesFormatters, colorProcessors } =
+ usePluginsMerge(plugins);
useReducedMotion(); // a11y reduce motion (see: https://react-spring.dev/docs/utilities/use-reduced-motion)
return (
-
-
-
-
-
+
+
+
+
-
- {children}
-
-
-
-
-
+
+
+ {children}
+
+
+
+
+
+
);
});
diff --git a/packages/x-charts/src/ChartsTooltip/ChartsAxisTooltipContent.tsx b/packages/x-charts/src/ChartsTooltip/ChartsAxisTooltipContent.tsx
index c275f0a02493..08f59b0ec6f2 100644
--- a/packages/x-charts/src/ChartsTooltip/ChartsAxisTooltipContent.tsx
+++ b/packages/x-charts/src/ChartsTooltip/ChartsAxisTooltipContent.tsx
@@ -9,7 +9,7 @@ import { AxisDefaultized } from '../models/axis';
import { ChartsTooltipClasses } from './chartsTooltipClasses';
import { DefaultChartsAxisTooltipContent } from './DefaultChartsAxisTooltipContent';
import { isCartesianSeriesType } from '../internals/isCartesian';
-import colorGetter from '../internals/colorGetter';
+import { useColorProcessor } from '../hooks/useColor';
import { ZAxisContext } from '../context/ZAxisContextProvider';
import { useSeries } from '../hooks/useSeries';
@@ -63,6 +63,8 @@ function ChartsAxisTooltipContent(props: {
const { zAxisIds, zAxis } = React.useContext(ZAxisContext);
const series = useSeries();
+ const colorProcessors = useColorProcessor();
+
const USED_AXIS_ID = isXaxis ? xAxisIds[0] : yAxisIds[0];
const relevantSeries = React.useMemo(() => {
@@ -76,31 +78,33 @@ function ChartsAxisTooltipContent(props: {
if (axisKey === undefined || axisKey === USED_AXIS_ID) {
const seriesToAdd = series[seriesType]!.series[seriesId];
- let getColor: (index: number) => string;
- switch (seriesToAdd.type) {
- case 'scatter':
- getColor = colorGetter(
- seriesToAdd,
- xAxis[seriesToAdd.xAxisKey ?? xAxisIds[0]],
- yAxis[seriesToAdd.yAxisKey ?? yAxisIds[0]],
- zAxis[seriesToAdd.zAxisKey ?? zAxisIds[0]],
- );
- break;
- default:
- getColor = colorGetter(
- seriesToAdd,
- xAxis[seriesToAdd.xAxisKey ?? xAxisIds[0]],
- yAxis[seriesToAdd.yAxisKey ?? yAxisIds[0]],
- );
- break;
- }
+ const zAxisKey = (seriesToAdd as any).zAxisKey ?? zAxisIds[0];
+
+ const getColor =
+ colorProcessors[seriesType]?.(
+ seriesToAdd as any,
+ xAxis[seriesToAdd.xAxisKey ?? xAxisIds[0]],
+ yAxis[seriesToAdd.yAxisKey ?? yAxisIds[0]],
+ zAxisKey && zAxis[zAxisKey],
+ ) ?? (() => '');
rep.push({ ...seriesToAdd, getColor });
}
});
});
return rep;
- }, [USED_AXIS_ID, isXaxis, series, xAxis, xAxisIds, yAxis, yAxisIds, zAxis, zAxisIds]);
+ }, [
+ USED_AXIS_ID,
+ colorProcessors,
+ isXaxis,
+ series,
+ xAxis,
+ xAxisIds,
+ yAxis,
+ yAxisIds,
+ zAxis,
+ zAxisIds,
+ ]);
const relevantAxis = React.useMemo(() => {
return isXaxis ? xAxis[USED_AXIS_ID] : yAxis[USED_AXIS_ID];
diff --git a/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx b/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx
index d77f16af9d47..ea0951a2d1a4 100644
--- a/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx
+++ b/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx
@@ -7,8 +7,8 @@ import { ChartSeriesDefaultized, ChartSeriesType } from '../models/seriesType/co
import { ChartsTooltipClasses } from './chartsTooltipClasses';
import { DefaultChartsItemTooltipContent } from './DefaultChartsItemTooltipContent';
import { CartesianContext } from '../context/CartesianContextProvider';
-import colorGetter from '../internals/colorGetter';
import { ZAxisContext } from '../context/ZAxisContextProvider';
+import { useColorProcessor } from '../hooks/useColor';
import { useSeries } from '../hooks/useSeries';
export type ChartsItemContentProps = {
@@ -46,32 +46,19 @@ function ChartsItemTooltipContent(props: {
const { xAxis, yAxis, xAxisIds, yAxisIds } = React.useContext(CartesianContext);
const { zAxis, zAxisIds } = React.useContext(ZAxisContext);
+ const colorProcessors = useColorProcessor();
- const defaultXAxisId = xAxisIds[0];
- const defaultYAxisId = yAxisIds[0];
- const defaultZAxisId = zAxisIds[0];
+ const xAxisKey = (series as any).xAxisKey ?? xAxisIds[0];
+ const yAxisKey = (series as any).yAxisKey ?? yAxisIds[0];
+ const zAxisKey = (series as any).zAxisKey ?? zAxisIds[0];
- let getColor: (index: number) => string;
- switch (series.type) {
- case 'pie':
- getColor = colorGetter(series);
- break;
- case 'scatter':
- getColor = colorGetter(
- series,
- xAxis[series.xAxisKey ?? defaultXAxisId],
- yAxis[series.yAxisKey ?? defaultYAxisId],
- zAxis[series.zAxisKey ?? defaultZAxisId],
- );
- break;
- default:
- getColor = colorGetter(
- series,
- xAxis[series.xAxisKey ?? defaultXAxisId],
- yAxis[series.yAxisKey ?? defaultYAxisId],
- );
- break;
- }
+ const getColor =
+ colorProcessors[series.type]?.(
+ series as any,
+ xAxisKey && xAxis[xAxisKey],
+ yAxisKey && yAxis[yAxisKey],
+ zAxisKey && zAxis[zAxisKey],
+ ) ?? (() => '');
const Content = content ?? DefaultChartsItemTooltipContent;
const chartTooltipContentProps = useSlotProps({
diff --git a/packages/x-charts/src/ChartsTooltip/DefaultChartsAxisTooltipContent.tsx b/packages/x-charts/src/ChartsTooltip/DefaultChartsAxisTooltipContent.tsx
index 0326ddc47294..5f76ce4edd6c 100644
--- a/packages/x-charts/src/ChartsTooltip/DefaultChartsAxisTooltipContent.tsx
+++ b/packages/x-charts/src/ChartsTooltip/DefaultChartsAxisTooltipContent.tsx
@@ -40,32 +40,28 @@ function DefaultChartsAxisTooltipContent(props: ChartsAxisContentProps) {
)}
- {series
- .filter(isCartesianSeries)
- .map(({ color, id, label, valueFormatter, data, getColor }) => {
- // @ts-ignore
- const formattedValue = valueFormatter(data[dataIndex] ?? null, { dataIndex });
- if (formattedValue == null) {
- return null;
- }
- const formattedLabel = getLabel(label, 'tooltip');
- return (
-
-
-
-
-
- {formattedLabel ? {formattedLabel} : null}
-
-
- {formattedValue}
-
-
- );
- })}
+ {series.filter(isCartesianSeries).map(({ id, label, valueFormatter, data, getColor }) => {
+ // @ts-ignore
+ const formattedValue = valueFormatter(data[dataIndex] ?? null, { dataIndex });
+ if (formattedValue == null) {
+ return null;
+ }
+ const formattedLabel = getLabel(label, 'tooltip');
+ const color = getColor(dataIndex);
+ return (
+
+
+ {color && }
+
+
+ {formattedLabel ? {formattedLabel} : null}
+
+
+ {formattedValue}
+
+
+ );
+ })}
diff --git a/packages/x-charts/src/ChartsTooltip/DefaultChartsItemTooltipContent.tsx b/packages/x-charts/src/ChartsTooltip/DefaultChartsItemTooltipContent.tsx
index 72bba158688b..29fb6f74338b 100644
--- a/packages/x-charts/src/ChartsTooltip/DefaultChartsItemTooltipContent.tsx
+++ b/packages/x-charts/src/ChartsTooltip/DefaultChartsItemTooltipContent.tsx
@@ -28,7 +28,7 @@ function DefaultChartsItemTooltipContent } = {
- bar: getBarExtremumX,
- scatter: getScatterExtremumX,
- line: getLineExtremumX,
-};
-
-const yExtremumGetters: { [T in CartesianChartSeriesType]: ExtremumGetter } = {
- bar: getBarExtremumY,
- scatter: getScatterExtremumY,
- line: getLineExtremumY,
-};
-
type DefaultizedAxisConfig = {
[axisKey: string]: AxisDefaultized;
};
@@ -111,7 +94,14 @@ if (process.env.NODE_ENV !== 'production') {
}
function CartesianContextProvider(props: CartesianContextProviderProps) {
- const { xAxis: inXAxis, yAxis: inYAxis, dataset, children } = props;
+ const {
+ xAxis: inXAxis,
+ yAxis: inYAxis,
+ dataset,
+ xExtremumGetters,
+ yExtremumGetters,
+ children,
+ } = props;
const formattedSeries = useSeries();
const drawingArea = useDrawingArea();
@@ -156,17 +146,17 @@ function CartesianContextProvider(props: CartesianContextProviderProps) {
acc: ExtremumGetterResult,
chartType: T,
axis: AxisConfig,
- getters: { [T2 in CartesianChartSeriesType]: ExtremumGetter },
+ getters: { [T2 in CartesianChartSeriesType]?: ExtremumGetter },
isDefaultAxis: boolean,
): ExtremumGetterResult => {
const getter = getters[chartType];
const series = (formattedSeries[chartType]?.series as Record>) ?? {};
- const [minChartTypeData, maxChartTypeData] = getter({
+ const [minChartTypeData, maxChartTypeData] = getter?.({
series,
axis,
isDefaultAxis,
- });
+ }) ?? [null, null];
const [minData, maxData] = acc;
@@ -183,7 +173,7 @@ function CartesianContextProvider(props: CartesianContextProviderProps) {
const getAxisExtremum = (
axis: AxisConfig,
- getters: { [T in CartesianChartSeriesType]: ExtremumGetter },
+ getters: { [T in CartesianChartSeriesType]?: ExtremumGetter },
isDefaultAxis: boolean,
) => {
const charTypes = Object.keys(getters) as CartesianChartSeriesType[];
@@ -356,7 +346,9 @@ function CartesianContextProvider(props: CartesianContextProviderProps) {
drawingArea.width,
formattedSeries,
xAxis,
+ xExtremumGetters,
yAxis,
+ yExtremumGetters,
]);
// @ts-ignore
diff --git a/packages/x-charts/src/context/ColorProvider.tsx b/packages/x-charts/src/context/ColorProvider.tsx
new file mode 100644
index 000000000000..46faebddded3
--- /dev/null
+++ b/packages/x-charts/src/context/ColorProvider.tsx
@@ -0,0 +1,22 @@
+import * as React from 'react';
+import { ColorProcessorsConfig } from '../models';
+import { ChartSeriesType } from '../internals';
+
+export interface ColorProviderProps {
+ children: React.ReactNode;
+ /**
+ * A mapping defining for each series type how to get item colors.
+ */
+ colorProcessors: ColorProcessorsConfig;
+}
+export const ColorContext = React.createContext({});
+
+if (process.env.NODE_ENV !== 'production') {
+ ColorContext.displayName = 'ColorContext';
+}
+
+export function ColorProvider(props: ColorProviderProps) {
+ const { colorProcessors, children } = props;
+
+ return {children} ;
+}
diff --git a/packages/x-charts/src/hooks/index.ts b/packages/x-charts/src/hooks/index.ts
index c052b357e379..148bf66d030b 100644
--- a/packages/x-charts/src/hooks/index.ts
+++ b/packages/x-charts/src/hooks/index.ts
@@ -1,6 +1,7 @@
export * from './useDrawingArea';
export * from './useChartId';
export * from './useScale';
+export * from './useColorScale';
export * from './useSvgRef';
export {
useSeries as unstable_useSeries,
diff --git a/packages/x-charts/src/hooks/useColor.ts b/packages/x-charts/src/hooks/useColor.ts
new file mode 100644
index 000000000000..c124c75cd796
--- /dev/null
+++ b/packages/x-charts/src/hooks/useColor.ts
@@ -0,0 +1,18 @@
+import * as React from 'react';
+import { ChartSeriesType } from '../internals';
+import { ColorContext } from '../context/ColorProvider';
+import { ColorProcessorsConfig } from '../models/plugin';
+
+export function useColorProcessor(
+ seriesType: T,
+): ColorProcessorsConfig;
+export function useColorProcessor(): ColorProcessorsConfig;
+export function useColorProcessor(seriesType?: ChartSeriesType) {
+ const colorProcessors = React.useContext(ColorContext);
+
+ if (!seriesType) {
+ return colorProcessors;
+ }
+
+ return colorProcessors[seriesType];
+}
diff --git a/packages/x-charts/src/hooks/useColorScale.ts b/packages/x-charts/src/hooks/useColorScale.ts
new file mode 100644
index 000000000000..947d2acbd6de
--- /dev/null
+++ b/packages/x-charts/src/hooks/useColorScale.ts
@@ -0,0 +1,34 @@
+import * as React from 'react';
+import { CartesianContext } from '../context/CartesianContextProvider';
+import { AxisScaleComputedConfig, ScaleName } from '../models/axis';
+import { ZAxisContext } from '../context/ZAxisContextProvider';
+
+export function useXColorScale(
+ identifier?: number | string,
+): AxisScaleComputedConfig[S]['colorScale'] | undefined {
+ const { xAxis, xAxisIds } = React.useContext(CartesianContext);
+
+ const id = typeof identifier === 'string' ? identifier : xAxisIds[identifier ?? 0];
+
+ return xAxis[id].colorScale;
+}
+
+export function useYColorScale(
+ identifier?: number | string,
+): AxisScaleComputedConfig[S]['colorScale'] | undefined {
+ const { yAxis, yAxisIds } = React.useContext(CartesianContext);
+
+ const id = typeof identifier === 'string' ? identifier : yAxisIds[identifier ?? 0];
+
+ return yAxis[id].colorScale;
+}
+
+export function useZColorScale(
+ identifier?: number | string,
+): AxisScaleComputedConfig[S]['colorScale'] | undefined {
+ const { zAxis, zAxisIds } = React.useContext(ZAxisContext);
+
+ const id = typeof identifier === 'string' ? identifier : zAxisIds[identifier ?? 0];
+
+ return zAxis[id]?.colorScale;
+}
diff --git a/packages/x-charts/src/internals/colorGetter.ts b/packages/x-charts/src/internals/colorGetter.ts
deleted file mode 100644
index 0b022ff91e25..000000000000
--- a/packages/x-charts/src/internals/colorGetter.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-import getBarColor from '../BarChart/getColor';
-import getLineColor from '../LineChart/getColor';
-import getScatterColor from '../ScatterChart/getColor';
-import getPieColor from '../PieChart/getColor';
-import {
- DefaultizedBarSeriesType,
- DefaultizedLineSeriesType,
- DefaultizedPieSeriesType,
- DefaultizedScatterSeriesType,
-} from '../models';
-import { AxisDefaultized } from '../models/axis';
-import { ZAxisDefaultized } from '../models/z-axis';
-
-function getColor(series: DefaultizedPieSeriesType): (dataIndex: number) => string;
-function getColor(
- series: DefaultizedBarSeriesType | DefaultizedLineSeriesType,
- xAxis: AxisDefaultized,
- yAxis: AxisDefaultized,
-): (dataIndex: number) => string;
-function getColor(
- series: DefaultizedScatterSeriesType,
- xAxis: AxisDefaultized,
- yAxis: AxisDefaultized,
- zAxis?: ZAxisDefaultized,
-): (dataIndex: number) => string;
-function getColor(
- series:
- | DefaultizedBarSeriesType
- | DefaultizedLineSeriesType
- | DefaultizedScatterSeriesType
- | DefaultizedPieSeriesType,
- xAxis?: AxisDefaultized,
- yAxis?: AxisDefaultized,
- zAxis?: ZAxisDefaultized,
-): (dataIndex: number) => string {
- if (xAxis !== undefined && yAxis !== undefined) {
- if (series.type === 'bar') {
- return getBarColor(series, xAxis, yAxis);
- }
-
- if (series.type === 'line') {
- return getLineColor(series, xAxis, yAxis);
- }
-
- if (series.type === 'scatter') {
- return getScatterColor(series, xAxis, yAxis, zAxis);
- }
- }
- if (series.type === 'pie') {
- return getPieColor(series);
- }
-
- throw Error(
- `MUI X Charts: getColor called with unexpected arguments for series with id "${series.id}"`,
- );
-}
-
-export default getColor;
diff --git a/packages/x-charts/src/internals/index.ts b/packages/x-charts/src/internals/index.ts
index b146ce17ee53..65de6514097d 100644
--- a/packages/x-charts/src/internals/index.ts
+++ b/packages/x-charts/src/internals/index.ts
@@ -1 +1,26 @@
+// Components
+export * from './components/ChartsAxesGradients';
+
+// hooks
+export { useReducedMotion } from '../hooks/useReducedMotion';
+export { useSeries } from '../hooks/useSeries';
+
+// utils
+export * from './defaultizeValueFormatter';
export * from './configInit';
+
+// contexts
+
+export * from '../context/CartesianContextProvider';
+export * from '../context/DrawingProvider';
+export * from '../context/InteractionProvider';
+export * from '../context/SeriesContextProvider';
+export * from '../context/ZAxisContextProvider';
+
+// series configuration
+export * from '../models/seriesType/config';
+export * from '../models/seriesType/common';
+
+export * from '../models/helpers';
+export * from '../models/z-axis';
+export * from '../models/axis';
diff --git a/packages/x-charts/src/models/axis.ts b/packages/x-charts/src/models/axis.ts
index 4b45e13c6e1e..2ca13a4836ff 100644
--- a/packages/x-charts/src/models/axis.ts
+++ b/packages/x-charts/src/models/axis.ts
@@ -214,7 +214,7 @@ export interface AxisScaleConfig {
};
}
-interface AxisScaleComputedConfig {
+export interface AxisScaleComputedConfig {
band: {
colorScale?:
| ScaleOrdinal
diff --git a/packages/x-data-grid/src/locales/beBY.ts b/packages/x-data-grid/src/locales/beBY.ts
index d2aaaa7729c5..b10dd30d81fd 100644
--- a/packages/x-data-grid/src/locales/beBY.ts
+++ b/packages/x-data-grid/src/locales/beBY.ts
@@ -4,16 +4,16 @@ import { getGridLocalization, Localization } from '../utils/getGridLocalization'
type PluralForm = {
one: string;
- twoToFour: string;
- other: string;
+ few: string;
+ many: string;
};
const getPluralForm = (count: number, options: PluralForm) => {
- let pluralForm = options.other;
+ let pluralForm = options.many;
const lastDigit = count % 10;
if (lastDigit > 1 && lastDigit < 5 && (count < 10 || count > 20)) {
- pluralForm = options.twoToFour;
+ pluralForm = options.few;
} else if (lastDigit === 1 && count % 100 !== 11) {
pluralForm = options.one;
}
@@ -45,8 +45,8 @@ const beBYGrid: Partial = {
toolbarFiltersTooltipActive: (count) =>
getPluralForm(count, {
one: 'актыўны фільтр',
- twoToFour: 'актыўных фільтра',
- other: 'актыўных фільтраў',
+ few: 'актыўных фільтра',
+ many: 'актыўных фільтраў',
}),
// Quick filter toolbar field
@@ -140,8 +140,8 @@ const beBYGrid: Partial = {
columnHeaderFiltersTooltipActive: (count) =>
getPluralForm(count, {
one: 'актыўны фільтр',
- twoToFour: 'актыўных фільтра',
- other: 'актыўных фільтраў',
+ few: 'актыўных фільтра',
+ many: 'актыўных фільтраў',
}),
columnHeaderFiltersLabel: 'Паказаць фільтры',
columnHeaderSortIconLabel: 'Сартыраваць',
@@ -150,8 +150,8 @@ const beBYGrid: Partial = {
footerRowSelected: (count) =>
getPluralForm(count, {
one: 'абраны радок',
- twoToFour: 'абраных радка',
- other: 'абраных радкоў',
+ few: 'абраных радка',
+ many: 'абраных радкоў',
}),
// Total row amount footer text
diff --git a/packages/x-data-grid/src/locales/ruRU.ts b/packages/x-data-grid/src/locales/ruRU.ts
index f08cfba7b4da..7312e34d60ba 100644
--- a/packages/x-data-grid/src/locales/ruRU.ts
+++ b/packages/x-data-grid/src/locales/ruRU.ts
@@ -2,6 +2,26 @@ import { ruRU as ruRUCore } from '@mui/material/locale';
import { GridLocaleText } from '../models/api/gridLocaleTextApi';
import { getGridLocalization, Localization } from '../utils/getGridLocalization';
+type PluralForm = {
+ one: string;
+ few: string;
+ many: string;
+};
+
+function getPluralForm(count: number, options: PluralForm) {
+ const penultimateDigit = Math.floor(count / 10) % 10;
+ const lastDigit = count % 10;
+
+ let pluralForm = options.many;
+ if (penultimateDigit !== 1 && lastDigit > 1 && lastDigit < 5) {
+ pluralForm = options.few;
+ } else if (penultimateDigit !== 1 && lastDigit === 1) {
+ pluralForm = options.one;
+ }
+
+ return `${count} ${pluralForm}`;
+}
+
const ruRUGrid: Partial = {
// Root
noRowsLabel: 'Нет строк',
@@ -23,16 +43,12 @@ const ruRUGrid: Partial = {
toolbarFiltersLabel: 'Показать фильтры',
toolbarFiltersTooltipHide: 'Скрыть фильтры',
toolbarFiltersTooltipShow: 'Показать фильтры',
- toolbarFiltersTooltipActive: (count) => {
- let pluralForm = 'активных фильтров';
- const lastDigit = count % 10;
- if (lastDigit > 1 && lastDigit < 5) {
- pluralForm = 'активных фильтра';
- } else if (lastDigit === 1) {
- pluralForm = 'активный фильтр';
- }
- return `${count} ${pluralForm}`;
- },
+ toolbarFiltersTooltipActive: (count) =>
+ getPluralForm(count, {
+ one: 'активный фильтр',
+ few: 'активных фильтра',
+ many: 'активных фильтров',
+ }),
// Quick filter toolbar field
toolbarQuickFilterPlaceholder: 'Поиск…',
@@ -122,30 +138,22 @@ const ruRUGrid: Partial = {
columnMenuSortDesc: 'Сортировать по убыванию',
// Column header text
- columnHeaderFiltersTooltipActive: (count) => {
- let pluralForm = 'активных фильтров';
- const lastDigit = count % 10;
- if (lastDigit > 1 && lastDigit < 5) {
- pluralForm = 'активных фильтра';
- } else if (lastDigit === 1) {
- pluralForm = 'активный фильтр';
- }
- return `${count} ${pluralForm}`;
- },
+ columnHeaderFiltersTooltipActive: (count) =>
+ getPluralForm(count, {
+ one: 'активный фильтр',
+ few: 'активных фильтра',
+ many: 'активных фильтров',
+ }),
columnHeaderFiltersLabel: 'Показать фильтры',
columnHeaderSortIconLabel: 'Сортировать',
// Rows selected footer text
- footerRowSelected: (count) => {
- let pluralForm = 'строк выбрано';
- const lastDigit = count % 10;
- if (lastDigit > 1 && lastDigit < 5) {
- pluralForm = 'строки выбраны';
- } else if (lastDigit === 1) {
- pluralForm = 'строка выбрана';
- }
- return `${count} ${pluralForm}`;
- },
+ footerRowSelected: (count) =>
+ getPluralForm(count, {
+ one: 'строка выбрана',
+ few: 'строки выбраны',
+ many: 'строк выбрано',
+ }),
// Total row amount footer text
footerTotalRows: 'Всего строк:',
diff --git a/packages/x-data-grid/src/locales/ukUA.ts b/packages/x-data-grid/src/locales/ukUA.ts
index 22185c2c34e9..bfb45ead7c68 100644
--- a/packages/x-data-grid/src/locales/ukUA.ts
+++ b/packages/x-data-grid/src/locales/ukUA.ts
@@ -8,18 +8,19 @@ type PluralForm = {
many: string;
};
-const getPluralForm = (count: number, options: PluralForm) => {
- let pluralForm = options.many;
+function getPluralForm(count: number, options: PluralForm) {
+ const penultimateDigit = Math.floor(count / 10) % 10;
const lastDigit = count % 10;
- if (lastDigit > 1 && lastDigit < 5) {
+ let pluralForm = options.many;
+ if (penultimateDigit !== 1 && lastDigit > 1 && lastDigit < 5) {
pluralForm = options.few;
- } else if (lastDigit === 1) {
+ } else if (penultimateDigit !== 1 && lastDigit === 1) {
pluralForm = options.one;
}
return `${count} ${pluralForm}`;
-};
+}
const ukUAGrid: Partial = {
// Root
diff --git a/packages/x-tree-view-pro/src/RichTreeViewPro/RichTreeViewPro.tsx b/packages/x-tree-view-pro/src/RichTreeViewPro/RichTreeViewPro.tsx
index 87433e941e9f..4294bc362a34 100644
--- a/packages/x-tree-view-pro/src/RichTreeViewPro/RichTreeViewPro.tsx
+++ b/packages/x-tree-view-pro/src/RichTreeViewPro/RichTreeViewPro.tsx
@@ -16,7 +16,10 @@ import {
RichTreeViewProSlotProps,
RichTreeViewProSlots,
} from './RichTreeViewPro.types';
-import { DEFAULT_TREE_VIEW_PRO_PLUGINS } from '../internals/plugins';
+import {
+ DEFAULT_TREE_VIEW_PRO_PLUGINS,
+ DefaultTreeViewProPluginSignatures,
+} from '../internals/plugins';
import { getReleaseInfo } from '../internals/utils/releaseInfo';
const useThemeProps = createUseThemeProps('MuiRichTreeViewPro');
@@ -102,7 +105,7 @@ const RichTreeViewPro = React.forwardRef(function RichTreeViewPro<
}
const { pluginParams, slots, slotProps, otherProps } = extractPluginParamsFromProps<
- typeof DEFAULT_TREE_VIEW_PRO_PLUGINS,
+ DefaultTreeViewProPluginSignatures,
RichTreeViewProSlots,
RichTreeViewProSlotProps,
RichTreeViewProProps
diff --git a/packages/x-tree-view-pro/src/RichTreeViewPro/RichTreeViewPro.types.ts b/packages/x-tree-view-pro/src/RichTreeViewPro/RichTreeViewPro.types.ts
index 7603b6fde12d..c0df5ad46263 100644
--- a/packages/x-tree-view-pro/src/RichTreeViewPro/RichTreeViewPro.types.ts
+++ b/packages/x-tree-view-pro/src/RichTreeViewPro/RichTreeViewPro.types.ts
@@ -11,7 +11,7 @@ import {
DefaultTreeViewProPluginParameters,
DefaultTreeViewProPluginSlotProps,
DefaultTreeViewProPluginSlots,
- DefaultTreeViewProPlugins,
+ DefaultTreeViewProPluginSignatures,
} from '../internals/plugins/defaultPlugins';
interface RichTreeViewItemProSlotOwnerState {
@@ -39,7 +39,7 @@ export interface RichTreeViewProSlotProps | undefined
+ TreeViewPublicAPI | undefined
>;
export interface RichTreeViewProPropsBase extends React.HTMLAttributes {
@@ -76,5 +76,5 @@ export interface RichTreeViewProProps;
+ experimentalFeatures?: TreeViewExperimentalFeatures;
}
diff --git a/packages/x-tree-view-pro/src/internals/plugins/defaultPlugins.ts b/packages/x-tree-view-pro/src/internals/plugins/defaultPlugins.ts
index 8f12846c5043..d720b6087266 100644
--- a/packages/x-tree-view-pro/src/internals/plugins/defaultPlugins.ts
+++ b/packages/x-tree-view-pro/src/internals/plugins/defaultPlugins.ts
@@ -13,7 +13,7 @@ import {
useTreeViewIcons,
UseTreeViewIconsParameters,
ConvertPluginsIntoSignatures,
- MergePluginsProperty,
+ MergeSignaturesProperty,
} from '@mui/x-tree-view/internals';
export const DEFAULT_TREE_VIEW_PRO_PLUGINS = [
@@ -26,17 +26,17 @@ export const DEFAULT_TREE_VIEW_PRO_PLUGINS = [
useTreeViewIcons,
] as const;
-export type DefaultTreeViewProPlugins = ConvertPluginsIntoSignatures<
+export type DefaultTreeViewProPluginSignatures = ConvertPluginsIntoSignatures<
typeof DEFAULT_TREE_VIEW_PRO_PLUGINS
>;
-export type DefaultTreeViewProPluginSlots = MergePluginsProperty<
- DefaultTreeViewProPlugins,
+export type DefaultTreeViewProPluginSlots = MergeSignaturesProperty<
+ DefaultTreeViewProPluginSignatures,
'slots'
>;
-export type DefaultTreeViewProPluginSlotProps = MergePluginsProperty<
- DefaultTreeViewProPlugins,
+export type DefaultTreeViewProPluginSlotProps = MergeSignaturesProperty<
+ DefaultTreeViewProPluginSignatures,
'slotProps'
>;
diff --git a/packages/x-tree-view-pro/src/internals/plugins/index.ts b/packages/x-tree-view-pro/src/internals/plugins/index.ts
index 43574e246824..96523fc22814 100644
--- a/packages/x-tree-view-pro/src/internals/plugins/index.ts
+++ b/packages/x-tree-view-pro/src/internals/plugins/index.ts
@@ -1,2 +1,2 @@
export { DEFAULT_TREE_VIEW_PRO_PLUGINS } from './defaultPlugins';
-export type { DefaultTreeViewProPlugins } from './defaultPlugins';
+export type { DefaultTreeViewProPluginSignatures } from './defaultPlugins';
diff --git a/packages/x-tree-view/src/RichTreeView/RichTreeView.tsx b/packages/x-tree-view/src/RichTreeView/RichTreeView.tsx
index 72c51f21549c..53f7f2257588 100644
--- a/packages/x-tree-view/src/RichTreeView/RichTreeView.tsx
+++ b/packages/x-tree-view/src/RichTreeView/RichTreeView.tsx
@@ -7,7 +7,7 @@ import { RichTreeViewProps, RichTreeViewSlotProps, RichTreeViewSlots } from './R
import { styled, createUseThemeProps } from '../internals/zero-styled';
import { useTreeView } from '../internals/useTreeView';
import { TreeViewProvider } from '../internals/TreeViewProvider';
-import { DEFAULT_TREE_VIEW_PLUGINS } from '../internals/plugins';
+import { DEFAULT_TREE_VIEW_PLUGINS, DefaultTreeViewPluginSignatures } from '../internals/plugins';
import { TreeItem, TreeItemProps } from '../TreeItem';
import { buildWarning } from '../internals/utils/warning';
import { extractPluginParamsFromProps } from '../internals/utils/extractPluginParamsFromProps';
@@ -91,7 +91,7 @@ const RichTreeView = React.forwardRef(function RichTreeView<
}
const { pluginParams, slots, slotProps, otherProps } = extractPluginParamsFromProps<
- typeof DEFAULT_TREE_VIEW_PLUGINS,
+ DefaultTreeViewPluginSignatures,
RichTreeViewSlots,
RichTreeViewSlotProps,
RichTreeViewProps
diff --git a/packages/x-tree-view/src/RichTreeView/RichTreeView.types.ts b/packages/x-tree-view/src/RichTreeView/RichTreeView.types.ts
index 974a665b69a4..9b71ae3c7a57 100644
--- a/packages/x-tree-view/src/RichTreeView/RichTreeView.types.ts
+++ b/packages/x-tree-view/src/RichTreeView/RichTreeView.types.ts
@@ -7,7 +7,7 @@ import {
DefaultTreeViewPluginParameters,
DefaultTreeViewPluginSlotProps,
DefaultTreeViewPluginSlots,
- DefaultTreeViewPlugins,
+ DefaultTreeViewPluginSignatures,
} from '../internals/plugins/defaultPlugins';
import { TreeItemProps } from '../TreeItem';
import { TreeItem2Props } from '../TreeItem2';
@@ -47,7 +47,7 @@ export interface RichTreeViewSlotProps | undefined
+ TreeViewPublicAPI | undefined
>;
export interface RichTreeViewPropsBase extends React.HTMLAttributes {
@@ -84,5 +84,5 @@ export interface RichTreeViewProps;
+ experimentalFeatures?: TreeViewExperimentalFeatures;
}
diff --git a/packages/x-tree-view/src/SimpleTreeView/SimpleTreeView.plugins.ts b/packages/x-tree-view/src/SimpleTreeView/SimpleTreeView.plugins.ts
index 7d2cabef636f..f380f55d4cda 100644
--- a/packages/x-tree-view/src/SimpleTreeView/SimpleTreeView.plugins.ts
+++ b/packages/x-tree-view/src/SimpleTreeView/SimpleTreeView.plugins.ts
@@ -12,7 +12,9 @@ export const SIMPLE_TREE_VIEW_PLUGINS = [
useTreeViewJSXItems,
] as const;
-export type SimpleTreeViewPlugins = ConvertPluginsIntoSignatures;
+export type SimpleTreeViewPluginSignatures = ConvertPluginsIntoSignatures<
+ typeof SIMPLE_TREE_VIEW_PLUGINS
+>;
export type SimpleTreeViewPluginSlots = DefaultTreeViewPluginSlots;
diff --git a/packages/x-tree-view/src/SimpleTreeView/SimpleTreeView.tsx b/packages/x-tree-view/src/SimpleTreeView/SimpleTreeView.tsx
index 736cfdaa9d09..7a159b1eda55 100644
--- a/packages/x-tree-view/src/SimpleTreeView/SimpleTreeView.tsx
+++ b/packages/x-tree-view/src/SimpleTreeView/SimpleTreeView.tsx
@@ -6,12 +6,12 @@ import { styled, createUseThemeProps } from '../internals/zero-styled';
import { getSimpleTreeViewUtilityClass } from './simpleTreeViewClasses';
import {
SimpleTreeViewProps,
- SimpleTreeViewSlotProps,
SimpleTreeViewSlots,
+ SimpleTreeViewSlotProps,
} from './SimpleTreeView.types';
import { useTreeView } from '../internals/useTreeView';
import { TreeViewProvider } from '../internals/TreeViewProvider';
-import { SIMPLE_TREE_VIEW_PLUGINS } from './SimpleTreeView.plugins';
+import { SIMPLE_TREE_VIEW_PLUGINS, SimpleTreeViewPluginSignatures } from './SimpleTreeView.plugins';
import { buildWarning } from '../internals/utils/warning';
import { extractPluginParamsFromProps } from '../internals/utils/extractPluginParamsFromProps';
@@ -76,7 +76,7 @@ const SimpleTreeView = React.forwardRef(function SimpleTreeView<
}
const { pluginParams, slots, slotProps, otherProps } = extractPluginParamsFromProps<
- typeof SIMPLE_TREE_VIEW_PLUGINS,
+ SimpleTreeViewPluginSignatures,
SimpleTreeViewSlots,
SimpleTreeViewSlotProps,
SimpleTreeViewProps & { items: any }
diff --git a/packages/x-tree-view/src/SimpleTreeView/SimpleTreeView.types.ts b/packages/x-tree-view/src/SimpleTreeView/SimpleTreeView.types.ts
index b7e0ddcbbcdb..958dbcbf8348 100644
--- a/packages/x-tree-view/src/SimpleTreeView/SimpleTreeView.types.ts
+++ b/packages/x-tree-view/src/SimpleTreeView/SimpleTreeView.types.ts
@@ -7,7 +7,7 @@ import {
SimpleTreeViewPluginParameters,
SimpleTreeViewPluginSlotProps,
SimpleTreeViewPluginSlots,
- SimpleTreeViewPlugins,
+ SimpleTreeViewPluginSignatures,
} from './SimpleTreeView.plugins';
import { TreeViewExperimentalFeatures, TreeViewPublicAPI } from '../internals/models';
@@ -24,7 +24,7 @@ export interface SimpleTreeViewSlotProps extends SimpleTreeViewPluginSlotProps {
}
export type SimpleTreeViewApiRef = React.MutableRefObject<
- TreeViewPublicAPI | undefined
+ TreeViewPublicAPI | undefined
>;
export interface SimpleTreeViewProps
@@ -60,5 +60,5 @@ export interface SimpleTreeViewProps
* For each feature, if the flag is not explicitly set to `true`,
* the feature will be fully disabled and any property / method call will not have any effect.
*/
- experimentalFeatures?: TreeViewExperimentalFeatures;
+ experimentalFeatures?: TreeViewExperimentalFeatures;
}
diff --git a/packages/x-tree-view/src/TreeItem/TreeItem.test.tsx b/packages/x-tree-view/src/TreeItem/TreeItem.test.tsx
index 6256ac0bb6a7..49a9702b6f23 100644
--- a/packages/x-tree-view/src/TreeItem/TreeItem.test.tsx
+++ b/packages/x-tree-view/src/TreeItem/TreeItem.test.tsx
@@ -2,14 +2,14 @@ import * as React from 'react';
import { expect } from 'chai';
import PropTypes from 'prop-types';
import { createRenderer } from '@mui/internal-test-utils';
-import { SimpleTreeViewPlugins } from '@mui/x-tree-view/SimpleTreeView/SimpleTreeView.plugins';
+import { SimpleTreeViewPluginSignatures } from '@mui/x-tree-view/SimpleTreeView/SimpleTreeView.plugins';
import { TreeItem, treeItemClasses as classes } from '@mui/x-tree-view/TreeItem';
import { TreeViewContextValue } from '@mui/x-tree-view/internals/TreeViewProvider';
import { TreeViewContext } from '@mui/x-tree-view/internals/TreeViewProvider/TreeViewContext';
import { describeConformance } from 'test/utils/describeConformance';
import { describeTreeView } from 'test/utils/tree-view/describeTreeView';
-const TEST_TREE_VIEW_CONTEXT_VALUE: TreeViewContextValue = {
+const TEST_TREE_VIEW_CONTEXT_VALUE: TreeViewContextValue = {
instance: {
isItemExpandable: () => false,
isItemExpanded: () => false,
diff --git a/packages/x-tree-view/src/TreeItem/TreeItem.tsx b/packages/x-tree-view/src/TreeItem/TreeItem.tsx
index 03622786ad53..fbc06f53a7f0 100644
--- a/packages/x-tree-view/src/TreeItem/TreeItem.tsx
+++ b/packages/x-tree-view/src/TreeItem/TreeItem.tsx
@@ -15,7 +15,7 @@ import { TreeItemContent } from './TreeItemContent';
import { treeItemClasses, getTreeItemUtilityClass } from './treeItemClasses';
import { TreeItemOwnerState, TreeItemProps } from './TreeItem.types';
import { useTreeViewContext } from '../internals/TreeViewProvider/useTreeViewContext';
-import { DefaultTreeViewPlugins } from '../internals/plugins';
+import { DefaultTreeViewPluginSignatures } from '../internals/plugins';
import { TreeViewCollapseIcon, TreeViewExpandIcon } from '../icons';
import { TreeItem2Provider } from '../TreeItem2Provider';
import { TreeViewItemDepthContext } from '../internals/TreeViewItemDepthContext';
@@ -186,7 +186,7 @@ export const TreeItem = React.forwardRef(function TreeItem(
disabledItemsFocusable,
indentationAtItemLevel,
instance,
- } = useTreeViewContext();
+ } = useTreeViewContext();
const depthContext = React.useContext(TreeViewItemDepthContext);
const props = useThemeProps({ props: inProps, name: 'MuiTreeItem' });
diff --git a/packages/x-tree-view/src/TreeItem/useTreeItemState.ts b/packages/x-tree-view/src/TreeItem/useTreeItemState.ts
index f429ac981d20..0da618865f95 100644
--- a/packages/x-tree-view/src/TreeItem/useTreeItemState.ts
+++ b/packages/x-tree-view/src/TreeItem/useTreeItemState.ts
@@ -1,12 +1,12 @@
import * as React from 'react';
import { useTreeViewContext } from '../internals/TreeViewProvider/useTreeViewContext';
-import { DefaultTreeViewPlugins } from '../internals/plugins';
+import { DefaultTreeViewPluginSignatures } from '../internals/plugins';
export function useTreeItemState(itemId: string) {
const {
instance,
selection: { multiSelect, checkboxSelection, disableSelection },
- } = useTreeViewContext();
+ } = useTreeViewContext();
const expandable = instance.isItemExpandable(itemId);
const expanded = instance.isItemExpanded(itemId);
diff --git a/packages/x-tree-view/src/hooks/useTreeItem2Utils/useTreeItem2Utils.tsx b/packages/x-tree-view/src/hooks/useTreeItem2Utils/useTreeItem2Utils.tsx
index 911322d47766..deff0a1d89e5 100644
--- a/packages/x-tree-view/src/hooks/useTreeItem2Utils/useTreeItem2Utils.tsx
+++ b/packages/x-tree-view/src/hooks/useTreeItem2Utils/useTreeItem2Utils.tsx
@@ -1,6 +1,6 @@
import * as React from 'react';
import { useTreeViewContext } from '../../internals/TreeViewProvider/useTreeViewContext';
-import { DefaultTreeViewPlugins } from '../../internals/plugins';
+import { DefaultTreeViewPluginSignatures } from '../../internals/plugins';
import type { UseTreeItem2Status } from '../../useTreeItem2';
interface UseTreeItem2Interactions {
@@ -31,7 +31,7 @@ export const useTreeItem2Utils = ({
const {
instance,
selection: { multiSelect },
- } = useTreeViewContext();
+ } = useTreeViewContext();
const status: UseTreeItem2Status = {
expandable: isItemExpandable(children),
diff --git a/packages/x-tree-view/src/hooks/useTreeViewApiRef.tsx b/packages/x-tree-view/src/hooks/useTreeViewApiRef.tsx
index 8ef984c57796..b27410f75737 100644
--- a/packages/x-tree-view/src/hooks/useTreeViewApiRef.tsx
+++ b/packages/x-tree-view/src/hooks/useTreeViewApiRef.tsx
@@ -1,10 +1,11 @@
import * as React from 'react';
import { TreeViewAnyPluginSignature, TreeViewPublicAPI } from '../internals/models';
-import { DefaultTreeViewPlugins } from '../internals';
+import { DefaultTreeViewPluginSignatures } from '../internals';
/**
* Hook that instantiates a [[TreeViewApiRef]].
*/
export const useTreeViewApiRef = <
- TPlugins extends readonly TreeViewAnyPluginSignature[] = DefaultTreeViewPlugins,
->() => React.useRef(undefined) as React.MutableRefObject | undefined>;
+ TSignatures extends readonly TreeViewAnyPluginSignature[] = DefaultTreeViewPluginSignatures,
+>() =>
+ React.useRef(undefined) as React.MutableRefObject | undefined>;
diff --git a/packages/x-tree-view/src/internals/TreeViewProvider/TreeViewProvider.tsx b/packages/x-tree-view/src/internals/TreeViewProvider/TreeViewProvider.tsx
index de246ec61ea3..d85512736950 100644
--- a/packages/x-tree-view/src/internals/TreeViewProvider/TreeViewProvider.tsx
+++ b/packages/x-tree-view/src/internals/TreeViewProvider/TreeViewProvider.tsx
@@ -8,8 +8,8 @@ import { TreeViewAnyPluginSignature } from '../models';
*
* @ignore - do not document.
*/
-export function TreeViewProvider(
- props: TreeViewProviderProps,
+export function TreeViewProvider(
+ props: TreeViewProviderProps,
) {
const { value, children } = props;
diff --git a/packages/x-tree-view/src/internals/TreeViewProvider/TreeViewProvider.types.ts b/packages/x-tree-view/src/internals/TreeViewProvider/TreeViewProvider.types.ts
index 2d42554e5d8d..f0af466f0f21 100644
--- a/packages/x-tree-view/src/internals/TreeViewProvider/TreeViewProvider.types.ts
+++ b/packages/x-tree-view/src/internals/TreeViewProvider/TreeViewProvider.types.ts
@@ -1,6 +1,6 @@
import * as React from 'react';
import {
- MergePluginsProperty,
+ MergeSignaturesProperty,
TreeItemWrapper,
TreeRootWrapper,
TreeViewAnyPluginSignature,
@@ -9,17 +9,21 @@ import {
TreeViewPublicAPI,
} from '../models';
-export type TreeViewContextValue =
- MergePluginsProperty & {
- instance: TreeViewInstance;
- publicAPI: TreeViewPublicAPI;
+export type TreeViewItemPluginsRunner = (
+ props: TProps,
+) => Required;
+
+export type TreeViewContextValue =
+ MergeSignaturesProperty & {
+ instance: TreeViewInstance;
+ publicAPI: TreeViewPublicAPI;
rootRef: React.RefObject;
- wrapItem: TreeItemWrapper;
- wrapRoot: TreeRootWrapper;
- runItemPlugins: (props: TProps) => Required;
+ wrapItem: TreeItemWrapper;
+ wrapRoot: TreeRootWrapper;
+ runItemPlugins: TreeViewItemPluginsRunner;
};
-export interface TreeViewProviderProps {
- value: TreeViewContextValue;
+export interface TreeViewProviderProps {
+ value: TreeViewContextValue;
children: React.ReactNode;
}
diff --git a/packages/x-tree-view/src/internals/TreeViewProvider/index.ts b/packages/x-tree-view/src/internals/TreeViewProvider/index.ts
index 28aff7c61d46..ffee8fb725aa 100644
--- a/packages/x-tree-view/src/internals/TreeViewProvider/index.ts
+++ b/packages/x-tree-view/src/internals/TreeViewProvider/index.ts
@@ -1,2 +1,6 @@
export { TreeViewProvider } from './TreeViewProvider';
-export type { TreeViewProviderProps, TreeViewContextValue } from './TreeViewProvider.types';
+export type {
+ TreeViewProviderProps,
+ TreeViewContextValue,
+ TreeViewItemPluginsRunner,
+} from './TreeViewProvider.types';
diff --git a/packages/x-tree-view/src/internals/TreeViewProvider/useTreeViewContext.ts b/packages/x-tree-view/src/internals/TreeViewProvider/useTreeViewContext.ts
index 8da83b9b56eb..62fbce3ad739 100644
--- a/packages/x-tree-view/src/internals/TreeViewProvider/useTreeViewContext.ts
+++ b/packages/x-tree-view/src/internals/TreeViewProvider/useTreeViewContext.ts
@@ -3,8 +3,8 @@ import { TreeViewAnyPluginSignature } from '../models';
import { TreeViewContext } from './TreeViewContext';
import { TreeViewContextValue } from './TreeViewProvider.types';
-export const useTreeViewContext = () => {
- const context = React.useContext(TreeViewContext) as TreeViewContextValue;
+export const useTreeViewContext = () => {
+ const context = React.useContext(TreeViewContext) as TreeViewContextValue;
if (context == null) {
throw new Error(
[
diff --git a/packages/x-tree-view/src/internals/corePlugins/corePlugins.ts b/packages/x-tree-view/src/internals/corePlugins/corePlugins.ts
index feb26ae78c80..0d55e29829ab 100644
--- a/packages/x-tree-view/src/internals/corePlugins/corePlugins.ts
+++ b/packages/x-tree-view/src/internals/corePlugins/corePlugins.ts
@@ -1,5 +1,5 @@
import { useTreeViewInstanceEvents } from './useTreeViewInstanceEvents';
-import { ConvertPluginsIntoSignatures, MergePlugins } from '../models';
+import { ConvertPluginsIntoSignatures } from '../models';
/**
* Internal plugins that create the tools used by the other plugins.
@@ -7,6 +7,6 @@ import { ConvertPluginsIntoSignatures, MergePlugins } from '../models';
*/
export const TREE_VIEW_CORE_PLUGINS = [useTreeViewInstanceEvents] as const;
-export type TreeViewCorePluginsSignature = MergePlugins<
- ConvertPluginsIntoSignatures
+export type TreeViewCorePluginSignatures = ConvertPluginsIntoSignatures<
+ typeof TREE_VIEW_CORE_PLUGINS
>;
diff --git a/packages/x-tree-view/src/internals/corePlugins/index.ts b/packages/x-tree-view/src/internals/corePlugins/index.ts
index 556277c739ce..55cb778e2bd9 100644
--- a/packages/x-tree-view/src/internals/corePlugins/index.ts
+++ b/packages/x-tree-view/src/internals/corePlugins/index.ts
@@ -1,2 +1,2 @@
export { TREE_VIEW_CORE_PLUGINS } from './corePlugins';
-export type { TreeViewCorePluginsSignature } from './corePlugins';
+export type { TreeViewCorePluginSignatures } from './corePlugins';
diff --git a/packages/x-tree-view/src/internals/index.ts b/packages/x-tree-view/src/internals/index.ts
index 9500d00e37f3..752818a77fa0 100644
--- a/packages/x-tree-view/src/internals/index.ts
+++ b/packages/x-tree-view/src/internals/index.ts
@@ -7,7 +7,7 @@ export type {
TreeViewPlugin,
TreeViewPluginSignature,
ConvertPluginsIntoSignatures,
- MergePluginsProperty,
+ MergeSignaturesProperty,
TreeViewPublicAPI,
TreeViewExperimentalFeatures,
} from './models';
@@ -15,7 +15,7 @@ export type {
// Plugins
export { DEFAULT_TREE_VIEW_PLUGINS } from './plugins/defaultPlugins';
export type {
- DefaultTreeViewPlugins,
+ DefaultTreeViewPluginSignatures,
DefaultTreeViewPluginSlots,
DefaultTreeViewPluginSlotProps,
} from './plugins/defaultPlugins';
diff --git a/packages/x-tree-view/src/internals/models/helpers.ts b/packages/x-tree-view/src/internals/models/helpers.ts
index d8b259e45f46..f404e670cd90 100644
--- a/packages/x-tree-view/src/internals/models/helpers.ts
+++ b/packages/x-tree-view/src/internals/models/helpers.ts
@@ -22,33 +22,31 @@ export type OptionalIfEmpty = keyof B extends never
? Partial>
: Record;
-export type MergePluginsProperty<
- TPlugins extends readonly any[],
+export type MergeSignaturesProperty<
+ TSignatures extends readonly any[],
TProperty extends keyof TreeViewAnyPluginSignature,
-> = TPlugins extends readonly [plugin: infer P, ...otherPlugin: infer R]
+> = TSignatures extends readonly [plugin: infer P, ...otherPlugin: infer R]
? P extends TreeViewAnyPluginSignature
- ? P[TProperty] & MergePluginsProperty
+ ? P[TProperty] & MergeSignaturesProperty
: {}
: {};
-export type ConvertPluginsIntoSignatures =
- TPlugins extends readonly [plugin: infer P, ...otherPlugin: infer R]
- ? P extends TreeViewPlugin
- ? [TSignature, ...ConvertPluginsIntoSignatures]
- : ConvertPluginsIntoSignatures
- : [];
+export type ConvertPluginsIntoSignatures<
+ TPlugins extends readonly TreeViewPlugin[],
+> = TPlugins extends readonly [plugin: infer TPlugin, ...otherPlugin: infer R]
+ ? R extends readonly TreeViewPlugin[]
+ ? TPlugin extends TreeViewPlugin
+ ? readonly [TSignature, ...ConvertPluginsIntoSignatures]
+ : never
+ : never
+ : [];
-export interface MergePlugins {
- state: MergePluginsProperty;
- instance: MergePluginsProperty;
- publicAPI: MergePluginsProperty;
- params: MergePluginsProperty;
- defaultizedParams: MergePluginsProperty;
- dependantPlugins: MergePluginsProperty;
- contextValue: MergePluginsProperty;
- slots: MergePluginsProperty;
- slotProps: MergePluginsProperty;
- events: MergePluginsProperty;
- models: MergePluginsProperty;
- experimentalFeatures: MergePluginsProperty;
-}
+export type ConvertSignaturesIntoPlugins<
+ TSignatures extends readonly TreeViewAnyPluginSignature[],
+> = TSignatures extends readonly [signature: infer TSignature, ...otherSignatures: infer R]
+ ? R extends readonly TreeViewAnyPluginSignature[]
+ ? TSignature extends TreeViewAnyPluginSignature
+ ? readonly [TreeViewPlugin, ...ConvertSignaturesIntoPlugins]
+ : never
+ : never
+ : [];
diff --git a/packages/x-tree-view/src/internals/models/plugin.ts b/packages/x-tree-view/src/internals/models/plugin.ts
index 0d85c8b61754..fd26dd4c42d7 100644
--- a/packages/x-tree-view/src/internals/models/plugin.ts
+++ b/packages/x-tree-view/src/internals/models/plugin.ts
@@ -1,9 +1,9 @@
import * as React from 'react';
import { EventHandlers } from '@mui/base/utils';
import { TreeViewExperimentalFeatures, TreeViewInstance, TreeViewModel } from './treeView';
-import type { MergePluginsProperty, OptionalIfEmpty } from './helpers';
+import type { MergeSignaturesProperty, OptionalIfEmpty } from './helpers';
import { TreeViewEventLookupElement } from './events';
-import type { TreeViewCorePluginsSignature } from '../corePlugins';
+import type { TreeViewCorePluginSignatures } from '../corePlugins';
import { TreeViewItemId } from '../../models';
export interface TreeViewPluginOptions {
@@ -86,20 +86,20 @@ export type TreeViewAnyPluginSignature = {
};
type TreeViewUsedPlugins = [
- TreeViewCorePluginsSignature,
+ ...TreeViewCorePluginSignatures,
...TSignature['dependantPlugins'],
];
export type TreeViewUsedParams =
- TSignature['params'] & MergePluginsProperty, 'params'>;
+ TSignature['params'] & MergeSignaturesProperty, 'params'>;
type TreeViewUsedDefaultizedParams =
TSignature['defaultizedParams'] &
- MergePluginsProperty, 'defaultizedParams'>;
+ MergeSignaturesProperty, 'defaultizedParams'>;
export type TreeViewUsedInstance =
TSignature['instance'] &
- MergePluginsProperty, 'instance'> & {
+ MergeSignaturesProperty, 'instance'> & {
/**
* Private property only defined in TypeScript to be able to access the plugin signature from the instance object.
*/
@@ -107,7 +107,7 @@ export type TreeViewUsedInstance
};
type TreeViewUsedState = TSignature['state'] &
- MergePluginsProperty, 'state'>;
+ MergeSignaturesProperty, 'state'>;
type TreeViewUsedExperimentalFeatures =
TreeViewExperimentalFeatures<[TSignature, ...TSignature['dependantPlugins']]>;
@@ -118,10 +118,10 @@ type RemoveSetValue>> = {
export type TreeViewUsedModels =
TSignature['models'] &
- RemoveSetValue, 'models'>>;
+ RemoveSetValue, 'models'>>;
export type TreeViewUsedEvents =
- TSignature['events'] & MergePluginsProperty, 'events'>;
+ TSignature['events'] & MergeSignaturesProperty, 'events'>;
export interface TreeViewItemPluginOptions extends TreeViewItemPluginResponse {
props: TProps;
diff --git a/packages/x-tree-view/src/internals/models/treeView.ts b/packages/x-tree-view/src/internals/models/treeView.ts
index 80937aa10b55..e513e0f8bff5 100644
--- a/packages/x-tree-view/src/internals/models/treeView.ts
+++ b/packages/x-tree-view/src/internals/models/treeView.ts
@@ -1,5 +1,6 @@
import type { TreeViewAnyPluginSignature } from './plugin';
-import type { MergePluginsProperty } from './helpers';
+import type { MergeSignaturesProperty } from './helpers';
+import type { TreeViewCorePluginSignatures } from '../corePlugins';
export interface TreeViewItemMeta {
id: string;
@@ -24,11 +25,11 @@ export interface TreeViewModel {
}
export type TreeViewInstance =
- MergePluginsProperty;
+ MergeSignaturesProperty<[...TreeViewCorePluginSignatures, ...TSignatures], 'instance'>;
export type TreeViewPublicAPI =
- MergePluginsProperty;
+ MergeSignaturesProperty<[...TreeViewCorePluginSignatures, ...TSignatures], 'publicAPI'>;
export type TreeViewExperimentalFeatures<
TSignatures extends readonly TreeViewAnyPluginSignature[],
-> = { [key in MergePluginsProperty]?: boolean };
+> = { [key in MergeSignaturesProperty]?: boolean };
diff --git a/packages/x-tree-view/src/internals/plugins/defaultPlugins.ts b/packages/x-tree-view/src/internals/plugins/defaultPlugins.ts
index f737c5dcc8c9..c6b376aac744 100644
--- a/packages/x-tree-view/src/internals/plugins/defaultPlugins.ts
+++ b/packages/x-tree-view/src/internals/plugins/defaultPlugins.ts
@@ -5,7 +5,7 @@ import { useTreeViewSelection, UseTreeViewSelectionParameters } from './useTreeV
import { useTreeViewFocus, UseTreeViewFocusParameters } from './useTreeViewFocus';
import { useTreeViewKeyboardNavigation } from './useTreeViewKeyboardNavigation';
import { useTreeViewIcons, UseTreeViewIconsParameters } from './useTreeViewIcons';
-import { ConvertPluginsIntoSignatures, MergePluginsProperty } from '../models';
+import { ConvertPluginsIntoSignatures, MergeSignaturesProperty } from '../models';
export const DEFAULT_TREE_VIEW_PLUGINS = [
useTreeViewId,
@@ -17,12 +17,17 @@ export const DEFAULT_TREE_VIEW_PLUGINS = [
useTreeViewIcons,
] as const;
-export type DefaultTreeViewPlugins = ConvertPluginsIntoSignatures;
+export type DefaultTreeViewPluginSignatures = ConvertPluginsIntoSignatures<
+ typeof DEFAULT_TREE_VIEW_PLUGINS
+>;
-export type DefaultTreeViewPluginSlots = MergePluginsProperty;
+export type DefaultTreeViewPluginSlots = MergeSignaturesProperty<
+ DefaultTreeViewPluginSignatures,
+ 'slots'
+>;
-export type DefaultTreeViewPluginSlotProps = MergePluginsProperty<
- DefaultTreeViewPlugins,
+export type DefaultTreeViewPluginSlotProps = MergeSignaturesProperty<
+ DefaultTreeViewPluginSignatures,
'slotProps'
>;
diff --git a/packages/x-tree-view/src/internals/plugins/index.ts b/packages/x-tree-view/src/internals/plugins/index.ts
index 8b18e513cab0..75445ff5057c 100644
--- a/packages/x-tree-view/src/internals/plugins/index.ts
+++ b/packages/x-tree-view/src/internals/plugins/index.ts
@@ -1,2 +1,2 @@
export { DEFAULT_TREE_VIEW_PLUGINS } from './defaultPlugins';
-export type { DefaultTreeViewPlugins } from './defaultPlugins';
+export type { DefaultTreeViewPluginSignatures } from './defaultPlugins';
diff --git a/packages/x-tree-view/src/internals/useTreeView/useTreeView.ts b/packages/x-tree-view/src/internals/useTreeView/useTreeView.ts
index 464da635e65e..1bc1b6ed2279 100644
--- a/packages/x-tree-view/src/internals/useTreeView/useTreeView.ts
+++ b/packages/x-tree-view/src/internals/useTreeView/useTreeView.ts
@@ -5,11 +5,11 @@ import {
TreeViewAnyPluginSignature,
TreeViewInstance,
TreeViewPlugin,
- ConvertPluginsIntoSignatures,
- MergePluginsProperty,
+ MergeSignaturesProperty,
TreeItemWrapper,
TreeRootWrapper,
TreeViewPublicAPI,
+ ConvertSignaturesIntoPlugins,
} from '../models';
import {
UseTreeViewDefaultizedParameters,
@@ -18,8 +18,8 @@ import {
UseTreeViewRootSlotProps,
} from './useTreeView.types';
import { useTreeViewModels } from './useTreeViewModels';
-import { TreeViewContextValue } from '../TreeViewProvider';
-import { TREE_VIEW_CORE_PLUGINS } from '../corePlugins';
+import { TreeViewContextValue, TreeViewItemPluginsRunner } from '../TreeViewProvider';
+import { TREE_VIEW_CORE_PLUGINS, TreeViewCorePluginSignatures } from '../corePlugins';
export function useTreeViewApiInitialization(
inputApiRef: React.MutableRefObject | undefined,
@@ -36,36 +36,37 @@ export function useTreeViewApiInitialization(
return fallbackPublicApiRef.current;
}
-export const useTreeView = []>(
- inParams: UseTreeViewParameters,
-): UseTreeViewReturnValue> => {
- const plugins = [...TREE_VIEW_CORE_PLUGINS, ...inParams.plugins];
- type Signatures = ConvertPluginsIntoSignatures;
+export const useTreeView = (
+ inParams: UseTreeViewParameters,
+): UseTreeViewReturnValue => {
+ type TSignaturesWithCorePluginSignatures = readonly [
+ ...TreeViewCorePluginSignatures,
+ ...TSignatures,
+ ];
+ const plugins = [
+ ...TREE_VIEW_CORE_PLUGINS,
+ ...inParams.plugins,
+ ] as unknown as ConvertSignaturesIntoPlugins;
const params = plugins.reduce((acc, plugin) => {
if (plugin.getDefaultizedParams) {
- return plugin.getDefaultizedParams(acc);
+ return plugin.getDefaultizedParams(acc) as typeof acc;
}
return acc;
- }, inParams) as unknown as UseTreeViewDefaultizedParameters;
+ }, inParams) as unknown as UseTreeViewDefaultizedParameters;
- const models = useTreeViewModels(
- plugins,
- params as MergePluginsProperty,
- );
- const instanceRef = React.useRef>(
- {} as TreeViewInstance,
- );
- const instance = instanceRef.current as TreeViewInstance;
+ const models = useTreeViewModels(plugins, params);
+ const instanceRef = React.useRef({} as TreeViewInstance);
+ const instance = instanceRef.current as TreeViewInstance;
- const publicAPI = useTreeViewApiInitialization>(inParams.apiRef);
+ const publicAPI = useTreeViewApiInitialization>(inParams.apiRef);
const innerRootRef: React.RefObject = React.useRef(null);
const handleRootRef = useForkRef(innerRootRef, inParams.rootRef);
const [state, setState] = React.useState(() => {
- const temp = {} as MergePluginsProperty;
+ const temp = {} as MergeSignaturesProperty;
plugins.forEach((plugin) => {
if (plugin.getInitialState) {
Object.assign(
@@ -78,48 +79,33 @@ export const useTreeView = (
- otherHandlers: TOther,
- ) => React.HTMLAttributes)[] = [];
- const contextValue = {
- publicAPI,
- instance: instance as TreeViewInstance,
- rootRef: innerRootRef,
- } as TreeViewContextValue;
-
- const runPlugin = (plugin: TreeViewPlugin) => {
- const pluginResponse = plugin({
- instance,
- params,
- slots: params.slots,
- slotProps: params.slotProps,
- experimentalFeatures: params.experimentalFeatures,
- state,
- setState,
- rootRef: innerRootRef,
- models,
+ const itemWrappers = plugins
+ .map((plugin) => plugin.wrapItem)
+ .filter((wrapItem): wrapItem is TreeItemWrapper => !!wrapItem);
+ const wrapItem: TreeItemWrapper = ({ itemId, children }) => {
+ let finalChildren: React.ReactNode = children;
+ itemWrappers.forEach((itemWrapper) => {
+ finalChildren = itemWrapper({ itemId, children: finalChildren, instance });
});
- if (pluginResponse.getRootProps) {
- rootPropsGetters.push(pluginResponse.getRootProps);
- }
-
- if (pluginResponse.publicAPI) {
- Object.assign(publicAPI, pluginResponse.publicAPI);
- }
+ return finalChildren;
+ };
- if (pluginResponse.instance) {
- Object.assign(instance, pluginResponse.instance);
- }
+ const rootWrappers = plugins
+ .map((plugin) => plugin.wrapRoot)
+ .filter((wrapRoot): wrapRoot is TreeRootWrapper => !!wrapRoot)
+ // The wrappers are reversed to ensure that the first wrapper is the outermost one.
+ .reverse();
+ const wrapRoot: TreeRootWrapper = ({ children }) => {
+ let finalChildren: React.ReactNode = children;
+ rootWrappers.forEach((rootWrapper) => {
+ finalChildren = rootWrapper({ children: finalChildren, instance });
+ });
- if (pluginResponse.contextValue) {
- Object.assign(contextValue, pluginResponse.contextValue);
- }
+ return finalChildren;
};
- plugins.forEach(runPlugin);
-
- contextValue.runItemPlugins = (itemPluginProps) => {
+ const runItemPlugins: TreeViewItemPluginsRunner = (itemPluginProps) => {
let finalRootRef: React.RefCallback | null = null;
let finalContentRef: React.RefCallback | null = null;
@@ -147,33 +133,50 @@ export const useTreeView = plugin.wrapItem)
- .filter((wrapItem): wrapItem is TreeItemWrapper => !!wrapItem);
- contextValue.wrapItem = ({ itemId, children }) => {
- let finalChildren: React.ReactNode = children;
- itemWrappers.forEach((itemWrapper) => {
- finalChildren = itemWrapper({ itemId, children: finalChildren, instance });
+ const contextValue = {
+ publicAPI,
+ wrapItem,
+ wrapRoot,
+ runItemPlugins,
+ instance: instance as TreeViewInstance,
+ rootRef: innerRootRef,
+ } as TreeViewContextValue;
+
+ const rootPropsGetters: ((
+ otherHandlers: TOther,
+ ) => React.HTMLAttributes)[] = [];
+ const runPlugin = (plugin: TreeViewPlugin) => {
+ const pluginResponse = plugin({
+ instance,
+ params,
+ slots: params.slots,
+ slotProps: params.slotProps,
+ experimentalFeatures: params.experimentalFeatures,
+ state,
+ setState,
+ rootRef: innerRootRef,
+ models,
});
- return finalChildren;
- };
+ if (pluginResponse.getRootProps) {
+ rootPropsGetters.push(pluginResponse.getRootProps);
+ }
- const rootWrappers = plugins
- .map((plugin) => plugin.wrapRoot)
- .filter((wrapRoot): wrapRoot is TreeRootWrapper => !!wrapRoot)
- // The wrappers are reversed to ensure that the first wrapper is the outermost one.
- .reverse();
+ if (pluginResponse.publicAPI) {
+ Object.assign(publicAPI, pluginResponse.publicAPI);
+ }
- contextValue.wrapRoot = ({ children }) => {
- let finalChildren: React.ReactNode = children;
- rootWrappers.forEach((rootWrapper) => {
- finalChildren = rootWrapper({ children: finalChildren, instance });
- });
+ if (pluginResponse.instance) {
+ Object.assign(instance, pluginResponse.instance);
+ }
- return finalChildren;
+ if (pluginResponse.contextValue) {
+ Object.assign(contextValue, pluginResponse.contextValue);
+ }
};
+ plugins.forEach(runPlugin);
+
const getRootProps = (
otherHandlers: TOther = {} as TOther,
) => {
@@ -193,7 +196,7 @@ export const useTreeView = [],
-> = UseTreeViewBaseParameters &
- MergePluginsProperty, 'params'>;
+export type UseTreeViewParameters =
+ UseTreeViewBaseParameters &
+ Omit, keyof UseTreeViewBaseParameters>;
export interface UseTreeViewBaseParameters<
- TPlugins extends readonly TreeViewPlugin[],
+ TSignatures extends readonly TreeViewAnyPluginSignature[],
> {
- apiRef:
- | React.MutableRefObject>>
- | undefined;
+ apiRef: React.MutableRefObject> | undefined;
rootRef?: React.Ref | undefined;
- plugins: TPlugins;
- slots: MergePluginsProperty, 'slots'>;
- slotProps: MergePluginsProperty, 'slotProps'>;
- experimentalFeatures: TreeViewExperimentalFeatures>;
+ plugins: ConvertSignaturesIntoPlugins;
+ slots: MergeSignaturesProperty;
+ slotProps: MergeSignaturesProperty;
+ experimentalFeatures: TreeViewExperimentalFeatures;
}
export type UseTreeViewDefaultizedParameters<
- TPlugins extends readonly TreeViewPlugin[],
-> = UseTreeViewBaseParameters &
- MergePluginsProperty, 'defaultizedParams'>;
+ TSignatures extends readonly TreeViewAnyPluginSignature[],
+> = UseTreeViewBaseParameters &
+ MergeSignaturesProperty<[...TreeViewCorePluginSignatures, ...TSignatures], 'defaultizedParams'>;
export interface UseTreeViewRootSlotProps
extends Pick<
@@ -42,11 +39,11 @@ export interface UseTreeViewRootSlotProps
ref: React.Ref;
}
-export interface UseTreeViewReturnValue {
+export interface UseTreeViewReturnValue {
getRootProps: (
otherHandlers?: TOther,
) => UseTreeViewRootSlotProps;
rootRef: React.RefCallback | null;
- contextValue: TreeViewContextValue;
- instance: TreeViewInstance;
+ contextValue: TreeViewContextValue;
+ instance: TreeViewInstance;
}
diff --git a/packages/x-tree-view/src/internals/useTreeView/useTreeViewModels.ts b/packages/x-tree-view/src/internals/useTreeView/useTreeViewModels.ts
index 4e785b9b08da..42d861fb7fa2 100644
--- a/packages/x-tree-view/src/internals/useTreeView/useTreeViewModels.ts
+++ b/packages/x-tree-view/src/internals/useTreeView/useTreeViewModels.ts
@@ -1,25 +1,19 @@
import * as React from 'react';
import {
TreeViewAnyPluginSignature,
- TreeViewPlugin,
- ConvertPluginsIntoSignatures,
- MergePluginsProperty,
+ ConvertSignaturesIntoPlugins,
+ MergeSignaturesProperty,
} from '../models';
/**
* Implements the same behavior as `useControlled` but for several models.
* The controlled models are never stored in the state, and the state is only updated if the model is not controlled.
*/
-export const useTreeViewModels = <
- TPlugins extends readonly TreeViewPlugin[],
->(
- plugins: TPlugins,
- props: MergePluginsProperty, 'defaultizedParams'>,
+export const useTreeViewModels = (
+ plugins: ConvertSignaturesIntoPlugins,
+ props: MergeSignaturesProperty,
) => {
- type DefaultizedParams = MergePluginsProperty<
- ConvertPluginsIntoSignatures,
- 'defaultizedParams'
- >;
+ type DefaultizedParams = MergeSignaturesProperty;
const modelsRef = React.useRef<{
[modelName: string]: {
@@ -65,7 +59,7 @@ export const useTreeViewModels = <
},
];
}),
- ) as MergePluginsProperty, 'models'>;
+ ) as MergeSignaturesProperty;
// We know that `modelsRef` do not vary across renders.
/* eslint-disable react-hooks/rules-of-hooks, react-hooks/exhaustive-deps */
diff --git a/packages/x-tree-view/src/internals/utils/extractPluginParamsFromProps.ts b/packages/x-tree-view/src/internals/utils/extractPluginParamsFromProps.ts
index 2f1f139aeb04..facfbd3bc3d0 100644
--- a/packages/x-tree-view/src/internals/utils/extractPluginParamsFromProps.ts
+++ b/packages/x-tree-view/src/internals/utils/extractPluginParamsFromProps.ts
@@ -1,24 +1,22 @@
import * as React from 'react';
import {
- ConvertPluginsIntoSignatures,
- MergePluginsProperty,
+ ConvertSignaturesIntoPlugins,
+ MergeSignaturesProperty,
+ TreeViewAnyPluginSignature,
TreeViewExperimentalFeatures,
- TreeViewPlugin,
TreeViewPublicAPI,
} from '../models';
import { UseTreeViewBaseParameters } from '../useTreeView/useTreeView.types';
export const extractPluginParamsFromProps = <
- TPlugins extends readonly TreeViewPlugin[],
- TSlots extends MergePluginsProperty,
- TSlotProps extends MergePluginsProperty,
+ TSignatures extends readonly TreeViewAnyPluginSignature[],
+ TSlots extends MergeSignaturesProperty,
+ TSlotProps extends MergeSignaturesProperty,
TProps extends {
slots?: TSlots;
slotProps?: TSlotProps;
- apiRef?: React.MutableRefObject<
- TreeViewPublicAPI> | undefined
- >;
- experimentalFeatures?: TreeViewExperimentalFeatures>;
+ apiRef?: React.MutableRefObject | undefined>;
+ experimentalFeatures?: TreeViewExperimentalFeatures;
},
>({
props: { slots, slotProps, apiRef, experimentalFeatures, ...props },
@@ -26,10 +24,10 @@ export const extractPluginParamsFromProps = <
rootRef,
}: {
props: TProps;
- plugins: TPlugins;
+ plugins: ConvertSignaturesIntoPlugins;
rootRef?: React.Ref;
}) => {
- type PluginParams = MergePluginsProperty