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] New API method: setItemExpansion #12595

Merged
Merged
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);
});
});
},
);
Loading
Loading