Skip to content

Commit

Permalink
[TreeView] Refactor the tree view internals to prepare for headless A…
Browse files Browse the repository at this point in the history
…PI (mui#13311)
  • Loading branch information
flaviendelangle authored and DungTiger committed Jul 23, 2024
1 parent 2fbd064 commit a899cfc
Show file tree
Hide file tree
Showing 29 changed files with 369 additions and 317 deletions.
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

0 comments on commit a899cfc

Please sign in to comment.