Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TreeView] Refactor the tree view internals to prepare for headless API #13311

Merged
merged 6 commits into from
Jun 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 10 additions & 27 deletions docs/data/tree-view/rich-tree-view/headless/LogExpandedItems.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
import * as React from 'react';
import { useThemeProps } from '@mui/material/styles';
import { useSlotProps } from '@mui/base/utils';
import Box from '@mui/material/Box';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';

import { RichTreeViewRoot } from '@mui/x-tree-view/RichTreeView';
import { TreeItem } from '@mui/x-tree-view/TreeItem';
import {
DEFAULT_TREE_VIEW_PLUGINS,
extractPluginParamsFromProps,
useTreeView,
TreeViewProvider,
} from '@mui/x-tree-view/internals';
RichTreeViewRoot,
RICH_TREE_VIEW_PLUGINS,
} from '@mui/x-tree-view/RichTreeView';
import { TreeItem } from '@mui/x-tree-view/TreeItem';
import { useTreeView, TreeViewProvider } from '@mui/x-tree-view/internals';

const useTreeViewLogExpanded = ({ params, models }) => {
const expandedStr = JSON.stringify(models.expandedItems.value);
Expand All @@ -37,25 +33,12 @@ useTreeViewLogExpanded.params = {
logMessage: true,
};

const TREE_VIEW_PLUGINS = [...DEFAULT_TREE_VIEW_PLUGINS, useTreeViewLogExpanded];

function TreeView(inProps) {
const themeProps = useThemeProps({ props: inProps, name: 'HeadlessTreeView' });
const ownerState = themeProps;
const TREE_VIEW_PLUGINS = [...RICH_TREE_VIEW_PLUGINS, useTreeViewLogExpanded];

const { pluginParams, otherProps } = extractPluginParamsFromProps({
props: themeProps,
function TreeView(props) {
const { getRootProps, contextValue, instance } = useTreeView({
plugins: TREE_VIEW_PLUGINS,
});

const { getRootProps, contextValue, instance } = useTreeView(pluginParams);

const rootProps = useSlotProps({
elementType: RichTreeViewRoot,
externalSlotProps: {},
externalForwardedProps: otherProps,
getSlotProps: getRootProps,
ownerState,
props,
});

const itemsToRender = instance.getItemsToRender();
Expand All @@ -70,7 +53,7 @@ function TreeView(inProps) {

return (
<TreeViewProvider value={contextValue}>
<RichTreeViewRoot {...rootProps}>
<RichTreeViewRoot {...getRootProps()}>
{itemsToRender.map(renderItem)}
</RichTreeViewRoot>
</TreeViewProvider>
Expand Down
50 changes: 18 additions & 32 deletions docs/data/tree-view/rich-tree-view/headless/LogExpandedItems.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,21 @@
import * as React from 'react';
import { useThemeProps } from '@mui/material/styles';
import { useSlotProps } from '@mui/base/utils';
import Box from '@mui/material/Box';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import { TreeViewBaseItem } from '@mui/x-tree-view/models';
import {
RichTreeViewPropsBase,
RichTreeViewRoot,
RICH_TREE_VIEW_PLUGINS,
RichTreeViewPluginParameters,
RichTreeViewPluginSlots,
RichTreeViewPluginSlotProps,
} from '@mui/x-tree-view/RichTreeView';
import { TreeItem } from '@mui/x-tree-view/TreeItem';
import {
UseTreeViewExpansionSignature,
TreeViewPlugin,
TreeViewPluginSignature,
DefaultTreeViewPluginParameters,
DefaultTreeViewPluginSlotProps,
DefaultTreeViewPluginSlots,
DEFAULT_TREE_VIEW_PLUGINS,
extractPluginParamsFromProps,
useTreeView,
TreeViewProvider,
ConvertPluginsIntoSignatures,
Expand Down Expand Up @@ -70,42 +67,31 @@ useTreeViewLogExpanded.params = {
};

export interface TreeViewProps<R extends {}, Multiple extends boolean | undefined>
extends DefaultTreeViewPluginParameters<R, Multiple>,
extends RichTreeViewPluginParameters<R, Multiple>,
TreeViewLogExpandedParameters,
RichTreeViewPropsBase {
slots?: DefaultTreeViewPluginSlots;
slotProps?: DefaultTreeViewPluginSlotProps;
slots?: RichTreeViewPluginSlots;
slotProps?: RichTreeViewPluginSlotProps;
}

const TREE_VIEW_PLUGINS = [
...DEFAULT_TREE_VIEW_PLUGINS,
...RICH_TREE_VIEW_PLUGINS,
useTreeViewLogExpanded,
] as const;

type TreeViewPluginSignatures = ConvertPluginsIntoSignatures<
typeof TREE_VIEW_PLUGINS
>;

function TreeView<R extends {}, Multiple extends boolean | undefined>(
inProps: TreeViewProps<R, Multiple>,
props: TreeViewProps<R, Multiple>,
) {
const themeProps = useThemeProps({ props: inProps, name: 'HeadlessTreeView' });
const ownerState = themeProps as TreeViewProps<any, any>;

const { pluginParams, otherProps } = extractPluginParamsFromProps<
ConvertPluginsIntoSignatures<typeof TREE_VIEW_PLUGINS>,
DefaultTreeViewPluginSlots,
DefaultTreeViewPluginSlotProps,
TreeViewProps<R, Multiple>
const { getRootProps, contextValue, instance } = useTreeView<
TreeViewPluginSignatures,
typeof props
>({
props: themeProps,
plugins: TREE_VIEW_PLUGINS,
});

const { getRootProps, contextValue, instance } = useTreeView(pluginParams);

const rootProps = useSlotProps({
elementType: RichTreeViewRoot,
externalSlotProps: {},
externalForwardedProps: otherProps,
getSlotProps: getRootProps,
ownerState,
props,
});

const itemsToRender = instance.getItemsToRender();
Expand All @@ -123,7 +109,7 @@ function TreeView<R extends {}, Multiple extends boolean | undefined>(

return (
<TreeViewProvider value={contextValue}>
<RichTreeViewRoot {...rootProps}>
<RichTreeViewRoot {...getRootProps()}>
{itemsToRender.map(renderItem)}
</RichTreeViewRoot>
</TreeViewProvider>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
MergeSignaturesProperty,
} from '@mui/x-tree-view/internals';

export const DEFAULT_TREE_VIEW_PRO_PLUGINS = [
export const RICH_TREE_VIEW_PRO_PLUGINS = [
useTreeViewId,
useTreeViewItems,
useTreeViewExpansion,
Expand All @@ -26,25 +26,23 @@ export const DEFAULT_TREE_VIEW_PRO_PLUGINS = [
useTreeViewIcons,
] as const;

export type DefaultTreeViewProPluginSignatures = ConvertPluginsIntoSignatures<
typeof DEFAULT_TREE_VIEW_PRO_PLUGINS
export type RichTreeViewProPluginSignatures = ConvertPluginsIntoSignatures<
typeof RICH_TREE_VIEW_PRO_PLUGINS
>;

export type DefaultTreeViewProPluginSlots = MergeSignaturesProperty<
DefaultTreeViewProPluginSignatures,
export type RichTreeViewProPluginSlots = MergeSignaturesProperty<
RichTreeViewProPluginSignatures,
'slots'
>;

export type DefaultTreeViewProPluginSlotProps = MergeSignaturesProperty<
DefaultTreeViewProPluginSignatures,
export type RichTreeViewProPluginSlotProps = MergeSignaturesProperty<
RichTreeViewProPluginSignatures,
'slotProps'
>;

// We can't infer this type from the plugin, otherwise we would lose the generics.
export interface DefaultTreeViewProPluginParameters<
R extends {},
Multiple extends boolean | undefined,
> extends UseTreeViewIdParameters,
export interface RichTreeViewProPluginParameters<R extends {}, Multiple extends boolean | undefined>
extends UseTreeViewIdParameters,
UseTreeViewItemsParameters<R>,
UseTreeViewExpansionParameters,
UseTreeViewFocusParameters,
Expand Down
35 changes: 11 additions & 24 deletions packages/x-tree-view-pro/src/RichTreeViewPro/RichTreeViewPro.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,14 @@ import composeClasses from '@mui/utils/composeClasses';
import { useLicenseVerifier, Watermark } from '@mui/x-license';
import { useSlotProps } from '@mui/base/utils';
import { TreeItem, TreeItemProps } from '@mui/x-tree-view/TreeItem';
import {
useTreeView,
TreeViewProvider,
buildWarning,
extractPluginParamsFromProps,
} from '@mui/x-tree-view/internals';
import { useTreeView, TreeViewProvider, buildWarning } from '@mui/x-tree-view/internals';
import { styled, createUseThemeProps } from '../internals/zero-styled';
import { getRichTreeViewProUtilityClass } from './richTreeViewProClasses';
import { RichTreeViewProProps } from './RichTreeViewPro.types';
import {
RichTreeViewProProps,
RichTreeViewProSlotProps,
RichTreeViewProSlots,
} from './RichTreeViewPro.types';
import {
DEFAULT_TREE_VIEW_PRO_PLUGINS,
DefaultTreeViewProPluginSignatures,
} from '../internals/plugins';
RICH_TREE_VIEW_PRO_PLUGINS,
RichTreeViewProPluginSignatures,
} from './RichTreeViewPro.plugins';
import { getReleaseInfo } from '../internals/utils/releaseInfo';

const useThemeProps = createUseThemeProps('MuiRichTreeViewPro');
Expand Down Expand Up @@ -104,26 +95,22 @@ const RichTreeViewPro = React.forwardRef(function RichTreeViewPro<
}
}

const { pluginParams, slots, slotProps, otherProps } = extractPluginParamsFromProps<
DefaultTreeViewProPluginSignatures,
RichTreeViewProSlots,
RichTreeViewProSlotProps<R, Multiple>,
RichTreeViewProProps<R, Multiple>
const { getRootProps, contextValue, instance } = useTreeView<
RichTreeViewProPluginSignatures,
typeof props
>({
props,
plugins: DEFAULT_TREE_VIEW_PRO_PLUGINS,
plugins: RICH_TREE_VIEW_PRO_PLUGINS,
rootRef: ref,
props,
});

const { getRootProps, contextValue, instance } = useTreeView(pluginParams);

const { slots, slotProps } = props;
const classes = useUtilityClasses(props);

const Root = slots?.root ?? RichTreeViewProRoot;
const rootProps = useSlotProps({
elementType: Root,
externalSlotProps: slotProps?.root,
externalForwardedProps: otherProps,
className: classes.root,
getSlotProps: getRootProps,
ownerState: props as RichTreeViewProProps<any, any>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,18 @@ import { TreeViewItemId } from '@mui/x-tree-view/models';
import { TreeViewPublicAPI, TreeViewExperimentalFeatures } from '@mui/x-tree-view/internals';
import { RichTreeViewProClasses } from './richTreeViewProClasses';
import {
DefaultTreeViewProPluginParameters,
DefaultTreeViewProPluginSlotProps,
DefaultTreeViewProPluginSlots,
DefaultTreeViewProPluginSignatures,
} from '../internals/plugins/defaultPlugins';
RichTreeViewProPluginParameters,
RichTreeViewProPluginSlotProps,
RichTreeViewProPluginSlots,
RichTreeViewProPluginSignatures,
} from './RichTreeViewPro.plugins';

interface RichTreeViewItemProSlotOwnerState {
itemId: TreeViewItemId;
label: string;
}

export interface RichTreeViewProSlots extends DefaultTreeViewProPluginSlots {
export interface RichTreeViewProSlots extends RichTreeViewProPluginSlots {
/**
* Element rendered at the root.
* @default RichTreeViewProRoot
Expand All @@ -33,13 +33,13 @@ export interface RichTreeViewProSlots extends DefaultTreeViewProPluginSlots {
}

export interface RichTreeViewProSlotProps<R extends {}, Multiple extends boolean | undefined>
extends DefaultTreeViewProPluginSlotProps {
extends RichTreeViewProPluginSlotProps {
root?: SlotComponentProps<'ul', {}, RichTreeViewProProps<R, Multiple>>;
item?: SlotComponentProps<typeof TreeItem, {}, RichTreeViewItemProSlotOwnerState>;
}

export type RichTreeViewProApiRef = React.MutableRefObject<
TreeViewPublicAPI<DefaultTreeViewProPluginSignatures> | undefined
TreeViewPublicAPI<RichTreeViewProPluginSignatures> | undefined
>;

export interface RichTreeViewProPropsBase extends React.HTMLAttributes<HTMLUListElement> {
Expand All @@ -55,7 +55,7 @@ export interface RichTreeViewProPropsBase extends React.HTMLAttributes<HTMLUList
}

export interface RichTreeViewProProps<R extends {}, Multiple extends boolean | undefined>
extends DefaultTreeViewProPluginParameters<R, Multiple>,
extends RichTreeViewProPluginParameters<R, Multiple>,
RichTreeViewProPropsBase {
/**
* Overridable component slots.
Expand All @@ -76,5 +76,5 @@ export interface RichTreeViewProProps<R extends {}, Multiple extends boolean | u
* 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<DefaultTreeViewProPluginSignatures>;
experimentalFeatures?: TreeViewExperimentalFeatures<RichTreeViewProPluginSignatures>;
}
2 changes: 0 additions & 2 deletions packages/x-tree-view-pro/src/internals/plugins/index.ts

This file was deleted.

56 changes: 56 additions & 0 deletions packages/x-tree-view/src/RichTreeView/RichTreeView.plugins.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { useTreeViewId, UseTreeViewIdParameters } from '../internals/plugins/useTreeViewId';
import {
useTreeViewItems,
UseTreeViewItemsParameters,
} from '../internals/plugins/useTreeViewItems';
import {
useTreeViewExpansion,
UseTreeViewExpansionParameters,
} from '../internals/plugins/useTreeViewExpansion';
import {
useTreeViewSelection,
UseTreeViewSelectionParameters,
} from '../internals/plugins/useTreeViewSelection';
import {
useTreeViewFocus,
UseTreeViewFocusParameters,
} from '../internals/plugins/useTreeViewFocus';
import { useTreeViewKeyboardNavigation } from '../internals/plugins/useTreeViewKeyboardNavigation';
import {
useTreeViewIcons,
UseTreeViewIconsParameters,
} from '../internals/plugins/useTreeViewIcons';
import { ConvertPluginsIntoSignatures, MergeSignaturesProperty } from '../internals/models';

export const RICH_TREE_VIEW_PLUGINS = [
useTreeViewId,
useTreeViewItems,
useTreeViewExpansion,
useTreeViewSelection,
useTreeViewFocus,
useTreeViewKeyboardNavigation,
useTreeViewIcons,
] as const;

export type RichTreeViewPluginSignatures = ConvertPluginsIntoSignatures<
typeof RICH_TREE_VIEW_PLUGINS
>;

export type RichTreeViewPluginSlots = MergeSignaturesProperty<
RichTreeViewPluginSignatures,
'slots'
>;

export type RichTreeViewPluginSlotProps = MergeSignaturesProperty<
RichTreeViewPluginSignatures,
'slotProps'
>;

// We can't infer this type from the plugin, otherwise we would lose the generics.
export interface RichTreeViewPluginParameters<R extends {}, Multiple extends boolean | undefined>
extends UseTreeViewIdParameters,
UseTreeViewItemsParameters<R>,
UseTreeViewExpansionParameters,
UseTreeViewFocusParameters,
UseTreeViewSelectionParameters<Multiple>,
UseTreeViewIconsParameters {}
Loading