From 05d37b71a8350eb83e14f84e357a766b2d9f5428 Mon Sep 17 00:00:00 2001 From: Flavien DELANGLE Date: Wed, 3 Apr 2024 16:58:58 +0200 Subject: [PATCH] [TreeView] New API method: `setItemExpansion` (#12595) Signed-off-by: Flavien DELANGLE Co-authored-by: Lukas --- .../expansion/ChangeItemExpansion.js | 51 +++++++++++++ .../expansion/ChangeItemExpansion.tsx | 51 +++++++++++++ .../expansion/ChangeItemExpansion.tsx.preview | 7 ++ .../rich-tree-view/expansion/expansion.md | 6 ++ .../expansion/ChangeItemExpansion.js | 41 +++++++++++ .../expansion/ChangeItemExpansion.tsx | 41 +++++++++++ .../simple-tree-view/expansion/expansion.md | 6 ++ .../pages/x/api/tree-view/rich-tree-view.json | 5 +- .../x/api/tree-view/simple-tree-view.json | 5 +- docs/pages/x/api/tree-view/tree-view.json | 5 +- .../src/RichTreeView/RichTreeView.tsx | 1 + .../src/SimpleTreeView/SimpleTreeView.tsx | 1 + .../src/TreeItem/TreeItem.test.tsx | 1 + .../x-tree-view/src/TreeView/TreeView.tsx | 1 + .../useTreeViewExpansion.test.tsx | 72 +++++++++++++++++++ .../useTreeViewExpansion.ts | 46 +++++++----- .../useTreeViewExpansion.types.ts | 15 +++- .../useTreeView/useTreeViewModels.ts | 4 +- .../describeTreeView/describeTreeView.tsx | 19 +++-- .../describeTreeView.types.ts | 10 ++- 20 files changed, 359 insertions(+), 29 deletions(-) create mode 100644 docs/data/tree-view/rich-tree-view/expansion/ChangeItemExpansion.js create mode 100644 docs/data/tree-view/rich-tree-view/expansion/ChangeItemExpansion.tsx create mode 100644 docs/data/tree-view/rich-tree-view/expansion/ChangeItemExpansion.tsx.preview create mode 100644 docs/data/tree-view/simple-tree-view/expansion/ChangeItemExpansion.js create mode 100644 docs/data/tree-view/simple-tree-view/expansion/ChangeItemExpansion.tsx diff --git a/docs/data/tree-view/rich-tree-view/expansion/ChangeItemExpansion.js b/docs/data/tree-view/rich-tree-view/expansion/ChangeItemExpansion.js new file mode 100644 index 0000000000000..044944e3dadcb --- /dev/null +++ b/docs/data/tree-view/rich-tree-view/expansion/ChangeItemExpansion.js @@ -0,0 +1,51 @@ +import * as React from 'react'; +import Box from '@mui/material/Box'; +import Stack from '@mui/material/Stack'; +import Button from '@mui/material/Button'; +import { RichTreeView } from '@mui/x-tree-view/RichTreeView'; + +import { useTreeViewApiRef } from '@mui/x-tree-view/hooks'; + +const MUI_X_PRODUCTS = [ + { + id: 'grid', + label: 'Data Grid', + children: [ + { id: 'grid-community', label: '@mui/x-data-grid' }, + { id: 'grid-pro', label: '@mui/x-data-grid-pro' }, + { id: 'grid-premium', label: '@mui/x-data-grid-premium' }, + ], + }, + { + id: 'pickers', + label: 'Date and Time Pickers', + children: [ + { id: 'pickers-community', label: '@mui/x-date-pickers' }, + { id: 'pickers-pro', label: '@mui/x-date-pickers-pro' }, + ], + }, +]; + +export default function ChangeItemExpansion() { + const apiRef = useTreeViewApiRef(); + + const handleExpandClick = (event) => { + apiRef.current.setItemExpansion(event, 'grid', true); + }; + + const handleCollapseClick = (event) => { + apiRef.current.setItemExpansion(event, 'grid', false); + }; + + return ( + + + + + + + + + + ); +} diff --git a/docs/data/tree-view/rich-tree-view/expansion/ChangeItemExpansion.tsx b/docs/data/tree-view/rich-tree-view/expansion/ChangeItemExpansion.tsx new file mode 100644 index 0000000000000..91587ed8df718 --- /dev/null +++ b/docs/data/tree-view/rich-tree-view/expansion/ChangeItemExpansion.tsx @@ -0,0 +1,51 @@ +import * as React from 'react'; +import Box from '@mui/material/Box'; +import Stack from '@mui/material/Stack'; +import Button from '@mui/material/Button'; +import { RichTreeView } from '@mui/x-tree-view/RichTreeView'; +import { TreeViewBaseItem } from '@mui/x-tree-view/models'; +import { useTreeViewApiRef } from '@mui/x-tree-view/hooks'; + +const MUI_X_PRODUCTS: TreeViewBaseItem[] = [ + { + id: 'grid', + label: 'Data Grid', + children: [ + { id: 'grid-community', label: '@mui/x-data-grid' }, + { id: 'grid-pro', label: '@mui/x-data-grid-pro' }, + { id: 'grid-premium', label: '@mui/x-data-grid-premium' }, + ], + }, + { + id: 'pickers', + label: 'Date and Time Pickers', + children: [ + { id: 'pickers-community', label: '@mui/x-date-pickers' }, + { id: 'pickers-pro', label: '@mui/x-date-pickers-pro' }, + ], + }, +]; + +export default function ChangeItemExpansion() { + const apiRef = useTreeViewApiRef(); + + const handleExpandClick = (event: React.MouseEvent) => { + apiRef.current!.setItemExpansion(event, 'grid', true); + }; + + const handleCollapseClick = (event: React.MouseEvent) => { + apiRef.current!.setItemExpansion(event, 'grid', false); + }; + + return ( + + + + + + + + + + ); +} diff --git a/docs/data/tree-view/rich-tree-view/expansion/ChangeItemExpansion.tsx.preview b/docs/data/tree-view/rich-tree-view/expansion/ChangeItemExpansion.tsx.preview new file mode 100644 index 0000000000000..ca89ea196b8b9 --- /dev/null +++ b/docs/data/tree-view/rich-tree-view/expansion/ChangeItemExpansion.tsx.preview @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/docs/data/tree-view/rich-tree-view/expansion/expansion.md b/docs/data/tree-view/rich-tree-view/expansion/expansion.md index 86a04e1b8c1f5..a44e1e07bdfb8 100644 --- a/docs/data/tree-view/rich-tree-view/expansion/expansion.md +++ b/docs/data/tree-view/rich-tree-view/expansion/expansion.md @@ -32,3 +32,9 @@ Learn more about the _Controlled and uncontrolled_ pattern in the [React documen Use the `onItemExpansionToggle` prop if you want to react to an item expansion change: {{"demo": "TrackItemExpansionToggle.js"}} + +## Change item expansion + +You can use the `setItemExpansion` API method to imperatively change the expansion of an item: + +{{"demo": "ChangeItemExpansion.js"}} diff --git a/docs/data/tree-view/simple-tree-view/expansion/ChangeItemExpansion.js b/docs/data/tree-view/simple-tree-view/expansion/ChangeItemExpansion.js new file mode 100644 index 0000000000000..7af3290f9f7ed --- /dev/null +++ b/docs/data/tree-view/simple-tree-view/expansion/ChangeItemExpansion.js @@ -0,0 +1,41 @@ +import * as React from 'react'; +import Box from '@mui/material/Box'; +import Stack from '@mui/material/Stack'; +import Button from '@mui/material/Button'; +import { SimpleTreeView } from '@mui/x-tree-view/SimpleTreeView'; +import { TreeItem } from '@mui/x-tree-view/TreeItem'; +import { useTreeViewApiRef } from '@mui/x-tree-view/hooks'; + +export default function ChangeItemExpansion() { + const apiRef = useTreeViewApiRef(); + + const handleExpandClick = (event) => { + apiRef.current.setItemExpansion(event, 'grid', true); + }; + + const handleCollapseClick = (event) => { + apiRef.current.setItemExpansion(event, 'grid', false); + }; + + return ( + + + + + + + + + + + + + + + + + + + + ); +} diff --git a/docs/data/tree-view/simple-tree-view/expansion/ChangeItemExpansion.tsx b/docs/data/tree-view/simple-tree-view/expansion/ChangeItemExpansion.tsx new file mode 100644 index 0000000000000..ceddc17a3a266 --- /dev/null +++ b/docs/data/tree-view/simple-tree-view/expansion/ChangeItemExpansion.tsx @@ -0,0 +1,41 @@ +import * as React from 'react'; +import Box from '@mui/material/Box'; +import Stack from '@mui/material/Stack'; +import Button from '@mui/material/Button'; +import { SimpleTreeView } from '@mui/x-tree-view/SimpleTreeView'; +import { TreeItem } from '@mui/x-tree-view/TreeItem'; +import { useTreeViewApiRef } from '@mui/x-tree-view/hooks'; + +export default function ChangeItemExpansion() { + const apiRef = useTreeViewApiRef(); + + const handleExpandClick = (event: React.MouseEvent) => { + apiRef.current!.setItemExpansion(event, 'grid', true); + }; + + const handleCollapseClick = (event: React.MouseEvent) => { + apiRef.current!.setItemExpansion(event, 'grid', false); + }; + + return ( + + + + + + + + + + + + + + + + + + + + ); +} diff --git a/docs/data/tree-view/simple-tree-view/expansion/expansion.md b/docs/data/tree-view/simple-tree-view/expansion/expansion.md index 296736f0d16a9..d984b1bfb8137 100644 --- a/docs/data/tree-view/simple-tree-view/expansion/expansion.md +++ b/docs/data/tree-view/simple-tree-view/expansion/expansion.md @@ -31,3 +31,9 @@ Learn more about the _Controlled and uncontrolled_ pattern in the [React documen Use the `onItemExpansionToggle` prop to trigger an action upon an item being expanded. {{"demo": "TrackItemExpansionToggle.js"}} + +## Change item expansion + +You can use the `setItemExpansion` API method to imperatively change the expansion of an item: + +{{"demo": "ChangeItemExpansion.js"}} diff --git a/docs/pages/x/api/tree-view/rich-tree-view.json b/docs/pages/x/api/tree-view/rich-tree-view.json index 8ec57fbf2e91e..fe0bf95c7f4cc 100644 --- a/docs/pages/x/api/tree-view/rich-tree-view.json +++ b/docs/pages/x/api/tree-view/rich-tree-view.json @@ -1,7 +1,10 @@ { "props": { "apiRef": { - "type": { "name": "shape", "description": "{ current?: { focusItem: func, getItem: func } }" } + "type": { + "name": "shape", + "description": "{ current?: { focusItem: func, getItem: func, setItemExpansion: func } }" + } }, "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, "defaultExpandedItems": { diff --git a/docs/pages/x/api/tree-view/simple-tree-view.json b/docs/pages/x/api/tree-view/simple-tree-view.json index 0a4bd4f7b2da1..8bdc52ded8fa7 100644 --- a/docs/pages/x/api/tree-view/simple-tree-view.json +++ b/docs/pages/x/api/tree-view/simple-tree-view.json @@ -1,7 +1,10 @@ { "props": { "apiRef": { - "type": { "name": "shape", "description": "{ current?: { focusItem: func, getItem: func } }" } + "type": { + "name": "shape", + "description": "{ current?: { focusItem: func, getItem: func, setItemExpansion: func } }" + } }, "children": { "type": { "name": "node" } }, "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, diff --git a/docs/pages/x/api/tree-view/tree-view.json b/docs/pages/x/api/tree-view/tree-view.json index 28823f6d6bf72..40a19d4f2817b 100644 --- a/docs/pages/x/api/tree-view/tree-view.json +++ b/docs/pages/x/api/tree-view/tree-view.json @@ -1,7 +1,10 @@ { "props": { "apiRef": { - "type": { "name": "shape", "description": "{ current?: { focusItem: func, getItem: func } }" } + "type": { + "name": "shape", + "description": "{ current?: { focusItem: func, getItem: func, setItemExpansion: func } }" + } }, "children": { "type": { "name": "node" } }, "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, diff --git a/packages/x-tree-view/src/RichTreeView/RichTreeView.tsx b/packages/x-tree-view/src/RichTreeView/RichTreeView.tsx index b2f700eb14ab2..d318156d22c67 100644 --- a/packages/x-tree-view/src/RichTreeView/RichTreeView.tsx +++ b/packages/x-tree-view/src/RichTreeView/RichTreeView.tsx @@ -153,6 +153,7 @@ RichTreeView.propTypes = { current: PropTypes.shape({ focusItem: PropTypes.func.isRequired, getItem: PropTypes.func.isRequired, + setItemExpansion: PropTypes.func.isRequired, }), }), /** diff --git a/packages/x-tree-view/src/SimpleTreeView/SimpleTreeView.tsx b/packages/x-tree-view/src/SimpleTreeView/SimpleTreeView.tsx index c78cd8dcd2538..83d072c510466 100644 --- a/packages/x-tree-view/src/SimpleTreeView/SimpleTreeView.tsx +++ b/packages/x-tree-view/src/SimpleTreeView/SimpleTreeView.tsx @@ -116,6 +116,7 @@ SimpleTreeView.propTypes = { current: PropTypes.shape({ focusItem: PropTypes.func.isRequired, getItem: PropTypes.func.isRequired, + setItemExpansion: PropTypes.func.isRequired, }), }), /** diff --git a/packages/x-tree-view/src/TreeItem/TreeItem.test.tsx b/packages/x-tree-view/src/TreeItem/TreeItem.test.tsx index 5ce12562dc86b..7206c6a56cfeb 100644 --- a/packages/x-tree-view/src/TreeItem/TreeItem.test.tsx +++ b/packages/x-tree-view/src/TreeItem/TreeItem.test.tsx @@ -24,6 +24,7 @@ const TEST_TREE_VIEW_CONTEXT_VALUE: TreeViewContextValue publicAPI: { focusItem: () => {}, getItem: () => ({}), + setItemExpansion: () => {}, }, runItemPlugins: () => ({ rootRef: null, contentRef: null }), wrapItem: ({ children }) => children, diff --git a/packages/x-tree-view/src/TreeView/TreeView.tsx b/packages/x-tree-view/src/TreeView/TreeView.tsx index 5d21d2a0d7aca..0bd1b90b6a4e3 100644 --- a/packages/x-tree-view/src/TreeView/TreeView.tsx +++ b/packages/x-tree-view/src/TreeView/TreeView.tsx @@ -93,6 +93,7 @@ TreeView.propTypes = { current: PropTypes.shape({ focusItem: PropTypes.func.isRequired, getItem: PropTypes.func.isRequired, + setItemExpansion: PropTypes.func.isRequired, }), }), /** diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.test.tsx b/packages/x-tree-view/src/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.test.tsx index fcc5bad1dd9bd..30efae2980dff 100644 --- a/packages/x-tree-view/src/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.test.tsx +++ b/packages/x-tree-view/src/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.test.tsx @@ -300,5 +300,77 @@ describeTreeView( expect(onItemExpansionToggle.lastCall.args[2]).to.equal(false); }); }); + + describe('setItemExpansion api method', () => { + it('should expand a collapsed item when calling the setItemExpansion method with `isExpanded=true`', () => { + const onItemExpansionToggle = spy(); + + const response = render({ + items: [{ id: '1', children: [{ id: '1.1' }] }], + onItemExpansionToggle, + }); + + act(() => { + response.apiRef.current.setItemExpansion({} as any, '1', true); + }); + + expect(response.isItemExpanded('1')).to.equal(true); + expect(onItemExpansionToggle.callCount).to.equal(1); + expect(onItemExpansionToggle.lastCall.args[1]).to.equal('1'); + expect(onItemExpansionToggle.lastCall.args[2]).to.equal(true); + }); + + it('should collapse an expanded item when calling the setItemExpansion method with `isExpanded=false`', () => { + const onItemExpansionToggle = spy(); + + const response = render({ + items: [{ id: '1', children: [{ id: '1.1' }] }], + defaultExpandedItems: ['1'], + onItemExpansionToggle, + }); + + act(() => { + response.apiRef.current.setItemExpansion({} as any, '1', false); + }); + + expect(response.isItemExpanded('1')).to.equal(false); + expect(onItemExpansionToggle.callCount).to.equal(1); + expect(onItemExpansionToggle.lastCall.args[1]).to.equal('1'); + expect(onItemExpansionToggle.lastCall.args[2]).to.equal(false); + }); + + it('should do nothing when calling the setItemExpansion method with `isExpanded=true` on an already expanded item', () => { + const onItemExpansionToggle = spy(); + + const response = render({ + items: [{ id: '1', children: [{ id: '1.1' }] }], + defaultExpandedItems: ['1'], + onItemExpansionToggle, + }); + + act(() => { + response.apiRef.current.setItemExpansion({} as any, '1', true); + }); + + expect(response.isItemExpanded('1')).to.equal(true); + expect(onItemExpansionToggle.callCount).to.equal(0); + }); + + it('should do nothing when calling the setItemExpansion method with `isExpanded=false` on an already collapsed item', () => { + const onItemExpansionToggle = spy(); + + const response = render({ + items: [{ id: '1', children: [{ id: '1.1' }] }], + onItemExpansionToggle, + }); + + act(() => { + response.apiRef.current.setItemExpansion({} as any, '1', false); + }); + + expect(response.isItemExpanded('1')).to.equal(false); + expect(onItemExpansionToggle.callCount).to.equal(0); + }); + }); }, ); diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.ts b/packages/x-tree-view/src/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.ts index 7fa1d771b5a4a..d7519b4b5f494 100644 --- a/packages/x-tree-view/src/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.ts +++ b/packages/x-tree-view/src/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.ts @@ -1,26 +1,33 @@ import * as React from 'react'; import useEventCallback from '@mui/utils/useEventCallback'; import { TreeViewPlugin } from '../../models'; -import { populateInstance } from '../../useTreeView/useTreeView.utils'; +import { populateInstance, populatePublicAPI } from '../../useTreeView/useTreeView.utils'; import { UseTreeViewExpansionSignature } from './useTreeViewExpansion.types'; +import { TreeViewItemId } from '../../../models'; export const useTreeViewExpansion: TreeViewPlugin = ({ instance, + publicAPI, params, models, }) => { + const expandedItemsMap = React.useMemo(() => { + const temp = new Map(); + models.expandedItems.value.forEach((id) => { + temp.set(id, true); + }); + + return temp; + }, [models.expandedItems.value]); + const setExpandedItems = (event: React.SyntheticEvent, value: string[]) => { params.onExpandedItemsChange?.(event, value); models.expandedItems.setControlledValue(value); }; const isItemExpanded = React.useCallback( - (itemId: string) => { - return Array.isArray(models.expandedItems.value) - ? models.expandedItems.value.indexOf(itemId) !== -1 - : false; - }, - [models.expandedItems.value], + (itemId: string) => expandedItemsMap.has(itemId), + [expandedItemsMap], ); const isItemExpandable = React.useCallback( @@ -28,23 +35,27 @@ export const useTreeViewExpansion: TreeViewPlugin [instance], ); - const toggleItemExpansion = useEventCallback( - (event: React.SyntheticEvent, itemId: string | null) => { - if (itemId == null) { + const toggleItemExpansion = useEventCallback((event: React.SyntheticEvent, itemId: string) => { + const isExpandedBefore = instance.isItemExpanded(itemId); + instance.setItemExpansion(event, itemId, !isExpandedBefore); + }); + + const setItemExpansion = useEventCallback( + (event: React.SyntheticEvent, itemId: string, isExpanded: boolean) => { + const isExpandedBefore = instance.isItemExpanded(itemId); + if (isExpandedBefore === isExpanded) { return; } - const isExpandedBefore = models.expandedItems.value.indexOf(itemId!) !== -1; - let newExpanded: string[]; - if (isExpandedBefore) { - newExpanded = models.expandedItems.value.filter((id) => id !== itemId); - } else { + if (isExpanded) { newExpanded = [itemId].concat(models.expandedItems.value); + } else { + newExpanded = models.expandedItems.value.filter((id) => id !== itemId); } if (params.onItemExpansionToggle) { - params.onItemExpansionToggle(event, itemId, !isExpandedBefore); + params.onItemExpansionToggle(event, itemId, isExpanded); } setExpandedItems(event, newExpanded); @@ -75,9 +86,12 @@ export const useTreeViewExpansion: TreeViewPlugin populateInstance(instance, { isItemExpanded, isItemExpandable, + setItemExpansion, toggleItemExpansion, expandAllSiblings, }); + + populatePublicAPI(publicAPI, { setItemExpansion }); }; useTreeViewExpansion.models = { diff --git a/packages/x-tree-view/src/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.types.ts b/packages/x-tree-view/src/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.types.ts index 9f261541492a6..0116e7d722eb4 100644 --- a/packages/x-tree-view/src/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.types.ts +++ b/packages/x-tree-view/src/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.types.ts @@ -2,10 +2,20 @@ import * as React from 'react'; import { DefaultizedProps, TreeViewPluginSignature } from '../../models'; import { UseTreeViewItemsSignature } from '../useTreeViewItems'; -export interface UseTreeViewExpansionInstance { +export interface UseTreeViewExpansionPublicAPI { + /** + * Change the expansion status of a given item. + * @param {React.SyntheticEvent} event The UI event that triggered the change. + * @param {string} itemId The id of the item to modify. + * @param {boolean} isExpanded The new expansion status of the given item. + */ + setItemExpansion: (event: React.SyntheticEvent, itemId: string, isExpanded: boolean) => void; +} + +export interface UseTreeViewExpansionInstance extends UseTreeViewExpansionPublicAPI { isItemExpanded: (itemId: string) => boolean; isItemExpandable: (itemId: string) => boolean; - toggleItemExpansion: (event: React.SyntheticEvent, value: string) => void; + toggleItemExpansion: (event: React.SyntheticEvent, itemId: string) => void; expandAllSiblings: (event: React.KeyboardEvent, itemId: string) => void; } @@ -49,6 +59,7 @@ export type UseTreeViewExpansionSignature = TreeViewPluginSignature<{ params: UseTreeViewExpansionParameters; defaultizedParams: UseTreeViewExpansionDefaultizedParameters; instance: UseTreeViewExpansionInstance; + publicAPI: UseTreeViewExpansionPublicAPI; modelNames: 'expandedItems'; dependantPlugins: [UseTreeViewItemsSignature]; }>; diff --git a/packages/x-tree-view/src/internals/useTreeView/useTreeViewModels.ts b/packages/x-tree-view/src/internals/useTreeView/useTreeViewModels.ts index 1d6bb801ed3b3..83b346ca9479f 100644 --- a/packages/x-tree-view/src/internals/useTreeView/useTreeViewModels.ts +++ b/packages/x-tree-view/src/internals/useTreeView/useTreeViewModels.ts @@ -48,9 +48,7 @@ export const useTreeViewModels = < const models = Object.fromEntries( Object.entries(modelsRef.current).map(([modelName, model]) => { - const value = model.isControlled - ? props[modelName as keyof DefaultizedParams] - : modelsState[modelName]; + const value = props[modelName as keyof DefaultizedParams] ?? modelsState[modelName]; return [ modelName, diff --git a/test/utils/tree-view/describeTreeView/describeTreeView.tsx b/test/utils/tree-view/describeTreeView/describeTreeView.tsx index 39eb00ad72ba0..507eaffcc1de0 100644 --- a/test/utils/tree-view/describeTreeView/describeTreeView.tsx +++ b/test/utils/tree-view/describeTreeView/describeTreeView.tsx @@ -5,7 +5,7 @@ import { RichTreeView } from '@mui/x-tree-view/RichTreeView'; import { SimpleTreeView } from '@mui/x-tree-view/SimpleTreeView'; import { TreeItem, treeItemClasses } from '@mui/x-tree-view/TreeItem'; import { TreeItem2 } from '@mui/x-tree-view/TreeItem2'; -import { TreeViewAnyPluginSignature } from '@mui/x-tree-view/internals/models'; +import { TreeViewAnyPluginSignature, TreeViewPublicAPI } from '@mui/x-tree-view/internals/models'; import { MuiRenderResult } from '@mui-internal/test-utils/createRenderer'; import { DescribeTreeViewTestRunner, @@ -22,7 +22,7 @@ const innerDescribeTreeView = ( const getUtils = ( result: MuiRenderResult, - ): Omit, 'setProps'> => { + ): Omit, 'setProps' | 'apiRef'> => { const getRoot = () => result.getByRole('tree'); const getAllItemRoots = () => result.queryAllByRole('treeitem'); @@ -59,9 +59,11 @@ const innerDescribeTreeView = ( ...other }) => { const items = rawItems as readonly DescribeTreeViewItem[]; + const apiRef = { current: undefined }; const result = render( @@ -78,6 +80,7 @@ const innerDescribeTreeView = ( return { setProps: result.setProps, + apiRef: apiRef as { current: TreeViewPublicAPI<[TPlugin]> }, ...getUtils(result), }; }; @@ -93,9 +96,11 @@ const innerDescribeTreeView = ( ...other }) => { const items = rawItems as readonly DescribeTreeViewItem[]; + const apiRef = { current: undefined }; const result = render( ( return { setProps: result.setProps, + apiRef: apiRef as { current: TreeViewPublicAPI<[TPlugin]> }, ...getUtils(result), }; }; @@ -128,6 +134,7 @@ const innerDescribeTreeView = ( }) => { const items = rawItems as readonly DescribeTreeViewItem[]; const Item = slots?.item ?? TreeItem; + const apiRef = { current: undefined }; const renderItem = (item: DescribeTreeViewItem) => ( ( ); const result = render( - + {items.map(renderItem)} , ); return { setProps: result.setProps, + apiRef: apiRef as { current: TreeViewPublicAPI<[TPlugin]> }, ...getUtils(result), }; }; @@ -164,6 +172,8 @@ const innerDescribeTreeView = ( }) => { const items = rawItems as readonly DescribeTreeViewItem[]; const Item = slots?.item ?? TreeItem2; + const apiRef = { current: undefined }; + const renderItem = (item: DescribeTreeViewItem) => ( ( ); const result = render( - + {items.map(renderItem)} , ); return { setProps: result.setProps, + apiRef: apiRef as { current: TreeViewPublicAPI<[TPlugin]> }, ...getUtils(result), }; }; diff --git a/test/utils/tree-view/describeTreeView/describeTreeView.types.ts b/test/utils/tree-view/describeTreeView/describeTreeView.types.ts index 9c5f3d59dba8f..992bd656f19c6 100644 --- a/test/utils/tree-view/describeTreeView/describeTreeView.types.ts +++ b/test/utils/tree-view/describeTreeView/describeTreeView.types.ts @@ -1,5 +1,9 @@ import * as React from 'react'; -import { TreeViewAnyPluginSignature, TreeViewUsedParams } from '@mui/x-tree-view/internals/models'; +import { + TreeViewAnyPluginSignature, + TreeViewPublicAPI, + TreeViewUsedParams, +} from '@mui/x-tree-view/internals/models'; import { TreeItemProps } from '@mui/x-tree-view/TreeItem'; import { TreeItem2Props } from '@mui/x-tree-view/TreeItem2'; @@ -13,6 +17,10 @@ export interface DescribeTreeViewRendererReturnValue>} props A subset of the props accepted by the Tree View. */ setProps: (props: Partial>) => void; + /** + * The ref object that allows Tree View manipulation. + */ + apiRef: { current: TreeViewPublicAPI<[TPlugin]> }; /** * Returns the `root` slot of the Tree View. * @returns {HTMLElement} `root` slot of the Tree View.