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

[RichTreeViewPro] Add virtualization #13520

Draft
wants to merge 60 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 45 commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
75449bd
[RichTreeViewPro] Add virtualization
flaviendelangle Jun 17, 2024
aa64768
Merge branch 'master' into virtualization-tree-view
flaviendelangle Jun 18, 2024
ee2e007
Work
flaviendelangle Jun 18, 2024
7251baf
Merge branch 'master' into virtualization-tree-view
flaviendelangle Jun 21, 2024
a4e6249
Work
flaviendelangle Jun 21, 2024
b80bc1a
Work
flaviendelangle Jun 21, 2024
72c47ba
Work
flaviendelangle Jun 21, 2024
adbf9ae
Work
flaviendelangle Jun 21, 2024
31daf38
Merge branch 'master' into virtualization-tree-view
flaviendelangle Jun 24, 2024
bad9fa9
Merge branch 'master' into virtualization-tree-view
flaviendelangle Jun 24, 2024
4af70c9
Work
flaviendelangle Jun 24, 2024
7fd7cf2
Work
flaviendelangle Jun 24, 2024
ead30ca
Work
flaviendelangle Jun 24, 2024
8c0cf9b
Merge branch 'master' into virtualization-tree-view
flaviendelangle Jun 25, 2024
037237a
Work
flaviendelangle Jun 25, 2024
daa5338
Add doc exampel
flaviendelangle Jun 25, 2024
dfb13b4
Fix
flaviendelangle Jun 25, 2024
5ab71c7
Fix CI
flaviendelangle Jun 25, 2024
bb52901
Fix CI
flaviendelangle Jun 25, 2024
b42c795
Move doc demo
flaviendelangle Jun 25, 2024
79d446e
Merge branch 'master' into virtualization-tree-view
flaviendelangle Jun 25, 2024
74e554e
Fix scrollbar
flaviendelangle Jun 25, 2024
3df506b
Work
flaviendelangle Jun 25, 2024
13e1a34
Work
flaviendelangle Jun 25, 2024
50159b7
CI
flaviendelangle Jun 25, 2024
8c9a2a5
CI
flaviendelangle Jun 25, 2024
e818d75
CI
flaviendelangle Jun 25, 2024
85d9318
Merge branch 'master' into virtualization-tree-view
flaviendelangle Jun 25, 2024
4a61728
Merge
flaviendelangle Jun 25, 2024
22fbd8c
Work
flaviendelangle Jun 26, 2024
6420171
Fix
flaviendelangle Jun 26, 2024
33780a3
Work
flaviendelangle Jun 26, 2024
8ecbb5b
Work
flaviendelangle Jun 26, 2024
11b5f92
Merge branch 'master' into virtualization-tree-view
flaviendelangle Jun 26, 2024
f69a751
Merge branch 'master' into virtualization-tree-view
flaviendelangle Jun 27, 2024
f8fbcec
Merge branch 'master' into virtualization-tree-view
flaviendelangle Jun 27, 2024
aaf1843
Work
flaviendelangle Jun 27, 2024
57ad1be
Fix
flaviendelangle Jun 27, 2024
a57cebd
Merge branch 'master' into virtualization-tree-view
flaviendelangle Jul 1, 2024
5ed0419
Use x-internals
flaviendelangle Jul 1, 2024
5d73433
Merge
flaviendelangle Jul 10, 2024
0f6c6fd
Merge branch 'master' into virtualization-tree-view
flaviendelangle Jul 11, 2024
337c226
Merge
flaviendelangle Jul 17, 2024
174f2c0
Merge branch 'master' into virtualization-tree-view
flaviendelangle Jul 17, 2024
87b79d9
Keep focused item mounted
flaviendelangle Jul 17, 2024
bd56769
Merge branch 'master' into virtualization-tree-view
flaviendelangle Jul 22, 2024
ae463c5
Merge
flaviendelangle Aug 1, 2024
9b7d0f8
Empty
flaviendelangle Aug 1, 2024
47fc275
Merge
flaviendelangle Aug 1, 2024
256e774
Merge branch 'master' into virtualization-tree-view
flaviendelangle Aug 6, 2024
e1cccca
Merge
flaviendelangle Aug 14, 2024
0e3e43b
Review: Olivier
flaviendelangle Aug 14, 2024
c7d6da7
Work
flaviendelangle Aug 14, 2024
1f1377f
Work
flaviendelangle Aug 14, 2024
9d56ebe
Fix
flaviendelangle Aug 14, 2024
b61be4a
Work
flaviendelangle Aug 14, 2024
60cec6b
Merge branch 'master' into virtualization-tree-view
flaviendelangle Aug 14, 2024
526a713
Use new utils
flaviendelangle Aug 14, 2024
0990411
Merge branch 'master' into virtualization-tree-view
flaviendelangle Aug 19, 2024
6640b09
Merge
flaviendelangle Sep 9, 2024
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
40 changes: 40 additions & 0 deletions docs/data/tree-view/rich-tree-view/items/Virtualization.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import * as React from 'react';
import Box from '@mui/material/Box';
import { RichTreeViewPro } from '@mui/x-tree-view-pro/RichTreeViewPro';
import { TreeItem2 } from '@mui/x-tree-view/TreeItem2';

const ITEMS = Array.from({ length: 10 }).map((_1, index) => ({
id: `${index}`,
label: `Item ${index}`,
children: Array.from({ length: 10 }).map((_2, index2) => ({
id: `${index}-${index2}`,
label: `Item ${index}-${index2}`,
children: Array.from({ length: 10 }).map((_3, index3) => ({
id: `${index}-${index2}-${index3}`,
label: `Item ${index}-${index2}-${index3}`,
children: Array.from({ length: 10 }).map((_4, index4) => ({
id: `${index}-${index2}-${index3}-${index4}`,
label: `Item ${index}-${index2}-${index3}-${index4}`,
})),
})),
})),
}));

const addChildrenToItem = (item) => {
return [item.id, ...(item.children ?? []).flatMap(addChildrenToItem)];
};

const flatItemIds = ITEMS.flatMap(addChildrenToItem);

export default function Virtualization() {
return (
<Box sx={{ height: 352, minWidth: 250 }}>
<RichTreeViewPro
items={ITEMS}
experimentalFeatures={{ virtualization: true }}
defaultExpandedItems={flatItemIds}
slots={{ item: TreeItem2 }}
/>
</Box>
);
}
41 changes: 41 additions & 0 deletions docs/data/tree-view/rich-tree-view/items/Virtualization.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import * as React from 'react';
import Box from '@mui/material/Box';
import { RichTreeViewPro } from '@mui/x-tree-view-pro/RichTreeViewPro';
import { TreeItem2 } from '@mui/x-tree-view/TreeItem2';
import { TreeViewBaseItem, TreeViewItemId } from '@mui/x-tree-view/models';

const ITEMS = Array.from({ length: 10 }).map((_1, index) => ({
id: `${index}`,
label: `Item ${index}`,
children: Array.from({ length: 10 }).map((_2, index2) => ({
id: `${index}-${index2}`,
label: `Item ${index}-${index2}`,
children: Array.from({ length: 10 }).map((_3, index3) => ({
id: `${index}-${index2}-${index3}`,
label: `Item ${index}-${index2}-${index3}`,
children: Array.from({ length: 10 }).map((_4, index4) => ({
id: `${index}-${index2}-${index3}-${index4}`,
label: `Item ${index}-${index2}-${index3}-${index4}`,
})),
})),
})),
}));

const addChildrenToItem = (item: TreeViewBaseItem): TreeViewItemId[] => {
flaviendelangle marked this conversation as resolved.
Show resolved Hide resolved
return [item.id, ...(item.children ?? []).flatMap(addChildrenToItem)];
};

const flatItemIds = ITEMS.flatMap(addChildrenToItem);

export default function Virtualization() {
return (
<Box sx={{ height: 352, minWidth: 250 }}>
<RichTreeViewPro
items={ITEMS}
experimentalFeatures={{ virtualization: true }}
defaultExpandedItems={flatItemIds}
slots={{ item: TreeItem2 }}
/>
</Box>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<RichTreeViewPro
items={ITEMS}
experimentalFeatures={{ virtualization: true }}
defaultExpandedItems={flatItemIds}
slots={{ item: TreeItem2 }}
/>
8 changes: 8 additions & 0 deletions docs/data/tree-view/rich-tree-view/items/items.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,14 @@ When it's set to true:

{{"demo": "DisabledItemsFocusable.js", "defaultCodeOpen": false}}

## Virtualization [<span class="plan-pro"></span>](/x/introduction/licensing/#pro-plan 'Pro plan')

:::warning
This is only a POC, a lot of the behaviors are potentially broken.
:::

{{"demo": "Virtualization.js"}}

## Imperative API

### Get an item by ID
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ import {
MergeSignaturesProperty,
TreeViewCorePluginParameters,
} from '@mui/x-tree-view/internals';
import {
useTreeViewVirtualization,
UseTreeViewVirtualizationParameters,
} from '../internals/plugins/useTreeViewVirtualization';

export const RICH_TREE_VIEW_PRO_PLUGINS = [
useTreeViewItems,
Expand All @@ -22,6 +26,7 @@ export const RICH_TREE_VIEW_PRO_PLUGINS = [
useTreeViewFocus,
useTreeViewKeyboardNavigation,
useTreeViewIcons,
useTreeViewVirtualization,
] as const;

export type RichTreeViewProPluginSignatures = ConvertPluginsIntoSignatures<
Expand All @@ -45,4 +50,5 @@ export interface RichTreeViewProPluginParameters<R extends {}, Multiple extends
UseTreeViewExpansionParameters,
UseTreeViewFocusParameters,
UseTreeViewSelectionParameters<Multiple>,
UseTreeViewIconsParameters {}
UseTreeViewIconsParameters,
UseTreeViewVirtualizationParameters {}
75 changes: 24 additions & 51 deletions packages/x-tree-view-pro/src/RichTreeViewPro/RichTreeViewPro.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import * as React from 'react';
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 } from '@mui/x-tree-view/internals';
import {
useTreeView,
TreeViewProvider,
buildWarning,
RichTreeViewItems,
} from '@mui/x-tree-view/internals';
import { Watermark } from '@mui/x-license';
import { styled, createUseThemeProps } from '../internals/zero-styled';
import { getRichTreeViewProUtilityClass } from './richTreeViewProClasses';
import { RichTreeViewProProps } from './RichTreeViewPro.types';
Expand All @@ -12,6 +16,7 @@ import {
RichTreeViewProPluginSignatures,
} from './RichTreeViewPro.plugins';
import { getReleaseInfo } from '../internals/utils/releaseInfo';
import { TreeViewVirtualScroller } from '../TreeViewVirtualScroller';

const useThemeProps = createUseThemeProps('MuiRichTreeViewPro');

Expand Down Expand Up @@ -43,26 +48,6 @@ type RichTreeViewProComponent = (<R extends {}, Multiple extends boolean | undef
props: RichTreeViewProProps<R, Multiple> & React.RefAttributes<HTMLUListElement>,
) => React.JSX.Element) & { propTypes?: any };

function WrappedTreeItem<R extends {}>({
slots,
slotProps,
label,
id,
itemId,
children,
}: Pick<RichTreeViewProProps<R, any>, 'slots' | 'slotProps'> &
Pick<TreeItemProps, 'id' | 'itemId' | 'children'> & { label: string }) {
const Item = slots?.item ?? TreeItem;
const itemProps = useSlotProps({
elementType: Item,
externalSlotProps: slotProps?.item,
additionalProps: { itemId, id, label },
ownerState: { itemId, label },
});

return <Item {...itemProps}>{children}</Item>;
}

const releaseInfo = getReleaseInfo();

const childrenWarning = buildWarning([
Expand All @@ -87,8 +72,6 @@ const RichTreeViewPro = React.forwardRef(function RichTreeViewPro<
>(inProps: RichTreeViewProProps<R, Multiple>, ref: React.Ref<HTMLUListElement>) {
const props = useThemeProps({ props: inProps, name: 'MuiRichTreeViewPro' });

useLicenseVerifier('x-tree-view-pro', releaseInfo);

if (process.env.NODE_ENV !== 'production') {
if ((props as any).children != null) {
childrenWarning();
Expand Down Expand Up @@ -116,34 +99,24 @@ const RichTreeViewPro = React.forwardRef(function RichTreeViewPro<
ownerState: props as RichTreeViewProProps<any, any>,
});

const itemsToRender = instance.getItemsToRender();

const renderItem = ({
label,
itemId,
id,
children,
}: ReturnType<typeof instance.getItemsToRender>[number]) => {
return (
<WrappedTreeItem
slots={slots}
slotProps={slotProps}
key={itemId}
label={label}
id={id}
itemId={itemId}
>
{children?.map(renderItem)}
</WrappedTreeItem>
);
};

return (
<TreeViewProvider value={contextValue}>
<Root {...rootProps}>
{itemsToRender.map(renderItem)}
<Watermark packageName="x-tree-view-pro" releaseInfo={releaseInfo} />
</Root>
{contextValue.virtualization.enabled ? (
<TreeViewVirtualScroller
{...rootProps}
slots={{ ...slots, root: Root }}
slotProps={slotProps}
/>
) : (
<Root {...rootProps} ref={ref}>
<RichTreeViewItems
slots={slots}
slotProps={slotProps}
itemsToRender={instance.getItemsToRender()}
/>
<Watermark packageName="x-tree-view-pro" releaseInfo={releaseInfo} />
</Root>
)}
</TreeViewProvider>
);
}) as RichTreeViewProComponent;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,41 +1,37 @@
import * as React from 'react';
import { Theme } from '@mui/material/styles';
import { SxProps } from '@mui/system';
import { SlotComponentProps } from '@mui/base/utils';
import { TreeItem, TreeItemProps } from '@mui/x-tree-view/TreeItem';
import { TreeItem2Props } from '@mui/x-tree-view/TreeItem2';
import { TreeViewItemId } from '@mui/x-tree-view/models';
import { TreeViewPublicAPI, TreeViewExperimentalFeatures } from '@mui/x-tree-view/internals';
import { SxProps } from '@mui/system';
import {
TreeViewPublicAPI,
TreeViewExperimentalFeatures,
MakeOptional,
} from '@mui/x-tree-view/internals';
import { RichTreeViewProClasses } from './richTreeViewProClasses';
import {
RichTreeViewProPluginParameters,
RichTreeViewProPluginSlotProps,
RichTreeViewProPluginSlots,
RichTreeViewProPluginSignatures,
} from './RichTreeViewPro.plugins';
import {
TreeViewVirtualScrollerSlots,
TreeViewVirtualScrollerSlotProps,
TreeViewVirtualScrollerProps,
} from '../TreeViewVirtualScroller';

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

export interface RichTreeViewProSlots extends RichTreeViewProPluginSlots {
/**
* Element rendered at the root.
* @default RichTreeViewProRoot
*/
root?: React.ElementType;
/**
* Custom component for the item.
* @default TreeItem.
*/
item?: React.JSXElementConstructor<TreeItemProps> | React.JSXElementConstructor<TreeItem2Props>;
}
export interface RichTreeViewProSlots
extends RichTreeViewProPluginSlots,
MakeOptional<TreeViewVirtualScrollerSlots, 'root'> {}

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

export type RichTreeViewProApiRef = React.MutableRefObject<
Expand Down Expand Up @@ -66,7 +62,7 @@ export interface RichTreeViewProProps<R extends {}, Multiple extends boolean | u
* The props used for each component slot.
* @default {}
*/
slotProps?: RichTreeViewProSlotProps<R, Multiple>;
slotProps?: RichTreeViewProSlotProps;
/**
* The ref object that allows Tree View manipulation. Can be instantiated with `useTreeViewApiRef()`.
*/
Expand Down
Loading