Skip to content

Commit

Permalink
[TreeView] New API method: setItemExpansion (#12595)
Browse files Browse the repository at this point in the history
Signed-off-by: Flavien DELANGLE <flaviendelangle@gmail.com>
Co-authored-by: Lukas <llukas.tyla@gmail.com>
  • Loading branch information
flaviendelangle and LukasTy committed Apr 3, 2024
1 parent 3fd72e3 commit b44c954
Show file tree
Hide file tree
Showing 20 changed files with 359 additions and 29 deletions.
Original file line number Diff line number Diff line change
@@ -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 (
<Box sx={{ flexGrow: 1, maxWidth: 400 }}>
<Stack sx={{ mb: 1 }} spacing={2} direction="row">
<Button onClick={handleExpandClick}>Expand Data Grid</Button>
<Button onClick={handleCollapseClick}>Collapse Data Grid</Button>
</Stack>
<Box sx={{ minHeight: 220, flexGrow: 1 }}>
<RichTreeView items={MUI_X_PRODUCTS} apiRef={apiRef} />
</Box>
</Box>
);
}
Original file line number Diff line number Diff line change
@@ -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 (
<Box sx={{ flexGrow: 1, maxWidth: 400 }}>
<Stack sx={{ mb: 1 }} spacing={2} direction="row">
<Button onClick={handleExpandClick}>Expand Data Grid</Button>
<Button onClick={handleCollapseClick}>Collapse Data Grid</Button>
</Stack>
<Box sx={{ minHeight: 220, flexGrow: 1 }}>
<RichTreeView items={MUI_X_PRODUCTS} apiRef={apiRef} />
</Box>
</Box>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<Stack sx={{ mb: 1 }} spacing={2} direction="row">
<Button onClick={handleExpandClick}>Expand Data Grid</Button>
<Button onClick={handleCollapseClick}>Collapse Data Grid</Button>
</Stack>
<Box sx={{ minHeight: 220, flexGrow: 1 }}>
<RichTreeView items={MUI_X_PRODUCTS} apiRef={apiRef} />
</Box>
6 changes: 6 additions & 0 deletions docs/data/tree-view/rich-tree-view/expansion/expansion.md
Original file line number Diff line number Diff line change
Expand Up @@ -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"}}
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 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 (
<Box sx={{ flexGrow: 1, maxWidth: 400 }}>
<Stack sx={{ mb: 1 }} spacing={2} direction="row">
<Button onClick={handleExpandClick}>Expand Data Grid</Button>
<Button onClick={handleCollapseClick}>Collapse Data Grid</Button>
</Stack>
<Box sx={{ minHeight: 220, flexGrow: 1 }}>
<SimpleTreeView apiRef={apiRef}>
<TreeItem itemId="grid" label="Data Grid">
<TreeItem itemId="grid-community" label="@mui/x-data-grid" />
<TreeItem itemId="grid-pro" label="@mui/x-data-grid-pro" />
<TreeItem itemId="grid-premium" label="@mui/x-data-grid-premium" />
</TreeItem>
<TreeItem itemId="pickers" label="Date and Time Pickers">
<TreeItem itemId="pickers-community" label="@mui/x-date-pickers" />
<TreeItem itemId="pickers-pro" label="@mui/x-date-pickers-pro" />
</TreeItem>
</SimpleTreeView>
</Box>
</Box>
);
}
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 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 (
<Box sx={{ flexGrow: 1, maxWidth: 400 }}>
<Stack sx={{ mb: 1 }} spacing={2} direction="row">
<Button onClick={handleExpandClick}>Expand Data Grid</Button>
<Button onClick={handleCollapseClick}>Collapse Data Grid</Button>
</Stack>
<Box sx={{ minHeight: 220, flexGrow: 1 }}>
<SimpleTreeView apiRef={apiRef}>
<TreeItem itemId="grid" label="Data Grid">
<TreeItem itemId="grid-community" label="@mui/x-data-grid" />
<TreeItem itemId="grid-pro" label="@mui/x-data-grid-pro" />
<TreeItem itemId="grid-premium" label="@mui/x-data-grid-premium" />
</TreeItem>
<TreeItem itemId="pickers" label="Date and Time Pickers">
<TreeItem itemId="pickers-community" label="@mui/x-date-pickers" />
<TreeItem itemId="pickers-pro" label="@mui/x-date-pickers-pro" />
</TreeItem>
</SimpleTreeView>
</Box>
</Box>
);
}
6 changes: 6 additions & 0 deletions docs/data/tree-view/simple-tree-view/expansion/expansion.md
Original file line number Diff line number Diff line change
Expand Up @@ -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"}}
5 changes: 4 additions & 1 deletion docs/pages/x/api/tree-view/rich-tree-view.json
Original file line number Diff line number Diff line change
@@ -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": {
Expand Down
5 changes: 4 additions & 1 deletion docs/pages/x/api/tree-view/simple-tree-view.json
Original file line number Diff line number Diff line change
@@ -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 } },
Expand Down
5 changes: 4 additions & 1 deletion docs/pages/x/api/tree-view/tree-view.json
Original file line number Diff line number Diff line change
@@ -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 } },
Expand Down
1 change: 1 addition & 0 deletions packages/x-tree-view/src/RichTreeView/RichTreeView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ RichTreeView.propTypes = {
current: PropTypes.shape({
focusItem: PropTypes.func.isRequired,
getItem: PropTypes.func.isRequired,
setItemExpansion: PropTypes.func.isRequired,
}),
}),
/**
Expand Down
1 change: 1 addition & 0 deletions packages/x-tree-view/src/SimpleTreeView/SimpleTreeView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ SimpleTreeView.propTypes = {
current: PropTypes.shape({
focusItem: PropTypes.func.isRequired,
getItem: PropTypes.func.isRequired,
setItemExpansion: PropTypes.func.isRequired,
}),
}),
/**
Expand Down
1 change: 1 addition & 0 deletions packages/x-tree-view/src/TreeItem/TreeItem.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const TEST_TREE_VIEW_CONTEXT_VALUE: TreeViewContextValue<SimpleTreeViewPlugins>
publicAPI: {
focusItem: () => {},
getItem: () => ({}),
setItemExpansion: () => {},
},
runItemPlugins: () => ({ rootRef: null, contentRef: null }),
wrapItem: ({ children }) => children,
Expand Down
1 change: 1 addition & 0 deletions packages/x-tree-view/src/TreeView/TreeView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ TreeView.propTypes = {
current: PropTypes.shape({
focusItem: PropTypes.func.isRequired,
getItem: PropTypes.func.isRequired,
setItemExpansion: PropTypes.func.isRequired,
}),
}),
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -300,5 +300,77 @@ describeTreeView<UseTreeViewExpansionSignature>(
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);
});
});
},
);

0 comments on commit b44c954

Please sign in to comment.