Skip to content

Commit

Permalink
[Treeview] Add node selection support (#18357)
Browse files Browse the repository at this point in the history
  • Loading branch information
joshwooding authored Feb 25, 2020
1 parent 4c396bd commit 92c66df
Show file tree
Hide file tree
Showing 19 changed files with 1,500 additions and 622 deletions.
1 change: 1 addition & 0 deletions docs/pages/api/tree-item.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ Any other props supplied will be provided to the root element (native element).
|:-----|:-------------|:------------|
| <span class="prop-name">root</span> | <span class="prop-name">.MuiTreeItem-root</span> | Styles applied to the root element.
| <span class="prop-name">expanded</span> | <span class="prop-name">.Mui-expanded</span> | Pseudo-class applied to the root element when expanded.
| <span class="prop-name">selected</span> | <span class="prop-name">.Mui-selected</span> | Pseudo-class applied to the root element when selected.
| <span class="prop-name">group</span> | <span class="prop-name">.MuiTreeItem-group</span> | Styles applied to the `role="group"` element.
| <span class="prop-name">content</span> | <span class="prop-name">.MuiTreeItem-content</span> | Styles applied to the tree node content.
| <span class="prop-name">iconContainer</span> | <span class="prop-name">.MuiTreeItem-iconContainer</span> | Styles applied to the tree node icon and collapse/expand icon.
Expand Down
5 changes: 5 additions & 0 deletions docs/pages/api/tree-view.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,13 @@ You can learn more about the difference by [reading this guide](/guides/minimizi
| <span class="prop-name">defaultExpanded</span> | <span class="prop-type">Array&lt;string&gt;</span> | <span class="prop-default">[]</span> | Expanded node ids. (Uncontrolled) |
| <span class="prop-name">defaultExpandIcon</span> | <span class="prop-type">node</span> | | The default icon used to expand the node. |
| <span class="prop-name">defaultParentIcon</span> | <span class="prop-type">node</span> | | The default icon displayed next to a parent node. This is applied to all parent nodes and can be overridden by the TreeItem `icon` prop. |
| <span class="prop-name">defaultSelected</span> | <span class="prop-type">Array&lt;string&gt;<br>&#124;&nbsp;string</span> | <span class="prop-default">[]</span> | Selected node ids. (Uncontrolled) When `multiSelect` is true this takes an array of strings; when false (default) a string. |
| <span class="prop-name">disableSelection</span> | <span class="prop-type">bool</span> | <span class="prop-default">false</span> | If `true` selection is disabled. |
| <span class="prop-name">expanded</span> | <span class="prop-type">Array&lt;string&gt;</span> | | Expanded node ids. (Controlled) |
| <span class="prop-name">multiSelect</span> | <span class="prop-type">bool</span> | <span class="prop-default">false</span> | If true `ctrl` and `shift` will trigger multiselect. |
| <span class="prop-name">onNodeSelect</span> | <span class="prop-type">func</span> | | Callback fired when tree items are selected/unselected.<br><br>**Signature:**<br>`function(event: object, value: undefined) => void`<br>*event:* The event source of the callback<br>*value:* of the selected nodes. When `multiSelect` is true this is an array of strings; when false (default) a string. |
| <span class="prop-name">onNodeToggle</span> | <span class="prop-type">func</span> | | Callback fired when tree items are expanded/collapsed.<br><br>**Signature:**<br>`function(event: object, nodeIds: array) => void`<br>*event:* The event source of the callback.<br>*nodeIds:* The ids of the expanded nodes. |
| <span class="prop-name">selected</span> | <span class="prop-type">Array&lt;string&gt;<br>&#124;&nbsp;string</span> | | Selected node ids. (Controlled) When `multiSelect` is true this takes an array of strings; when false (default) a string. |

The `ref` is forwarded to the root element.

Expand Down
13 changes: 10 additions & 3 deletions docs/src/pages/components/tree-view/ControlledTreeView.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,14 @@ const useStyles = makeStyles({
export default function ControlledTreeView() {
const classes = useStyles();
const [expanded, setExpanded] = React.useState([]);
const [selected, setSelected] = React.useState([]);

const handleChange = (event, nodes) => {
setExpanded(nodes);
const handleToggle = (event, nodeIds) => {
setExpanded(nodeIds);
};

const handleSelect = (event, nodeIds) => {
setSelected(nodeIds);
};

return (
Expand All @@ -27,7 +32,9 @@ export default function ControlledTreeView() {
defaultCollapseIcon={<ExpandMoreIcon />}
defaultExpandIcon={<ChevronRightIcon />}
expanded={expanded}
onNodeToggle={handleChange}
selected={selected}
onNodeToggle={handleToggle}
onNodeSelect={handleSelect}
>
<TreeItem nodeId="1" label="Applications">
<TreeItem nodeId="2" label="Calendar" />
Expand Down
13 changes: 10 additions & 3 deletions docs/src/pages/components/tree-view/ControlledTreeView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,14 @@ const useStyles = makeStyles({
export default function ControlledTreeView() {
const classes = useStyles();
const [expanded, setExpanded] = React.useState<string[]>([]);
const [selected, setSelected] = React.useState<string[]>([]);

const handleChange = (event: React.ChangeEvent<{}>, nodes: string[]) => {
setExpanded(nodes);
const handleToggle = (event: React.ChangeEvent<{}>, nodeIds: string[]) => {
setExpanded(nodeIds);
};

const handleSelect = (event: React.ChangeEvent<{}>, nodeIds: string[]) => {
setSelected(nodeIds);
};

return (
Expand All @@ -27,7 +32,9 @@ export default function ControlledTreeView() {
defaultCollapseIcon={<ExpandMoreIcon />}
defaultExpandIcon={<ChevronRightIcon />}
expanded={expanded}
onNodeToggle={handleChange}
selected={selected}
onNodeToggle={handleToggle}
onNodeSelect={handleSelect}
>
<TreeItem nodeId="1" label="Applications">
<TreeItem nodeId="2" label="Calendar" />
Expand Down
10 changes: 5 additions & 5 deletions docs/src/pages/components/tree-view/CustomizedTreeView.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { useSpring, animated } from 'react-spring/web.cjs'; // web.cjs is requir

function MinusSquare(props) {
return (
<SvgIcon fontSize="inherit" {...props}>
<SvgIcon fontSize="inherit" style={{ width: 14, height: 14 }} {...props}>
{/* tslint:disable-next-line: max-line-length */}
<path d="M22.047 22.074v0 0-20.147 0h-20.12v0 20.147 0h20.12zM22.047 24h-20.12q-.803 0-1.365-.562t-.562-1.365v-20.147q0-.776.562-1.351t1.365-.575h20.147q.776 0 1.351.575t.575 1.351v20.147q0 .803-.575 1.365t-1.378.562v0zM17.873 11.023h-11.826q-.375 0-.669.281t-.294.682v0q0 .401.294 .682t.669.281h11.826q.375 0 .669-.281t.294-.682v0q0-.401-.294-.682t-.669-.281z" />
</SvgIcon>
Expand All @@ -18,7 +18,7 @@ function MinusSquare(props) {

function PlusSquare(props) {
return (
<SvgIcon fontSize="inherit" {...props}>
<SvgIcon fontSize="inherit" style={{ width: 14, height: 14 }} {...props}>
{/* tslint:disable-next-line: max-line-length */}
<path d="M22.047 22.074v0 0-20.147 0h-20.12v0 20.147 0h20.12zM22.047 24h-20.12q-.803 0-1.365-.562t-.562-1.365v-20.147q0-.776.562-1.351t1.365-.575h20.147q.776 0 1.351.575t.575 1.351v20.147q0 .803-.575 1.365t-1.378.562v0zM17.873 12.977h-4.923v4.896q0 .401-.281.682t-.682.281v0q-.375 0-.669-.281t-.294-.682v-4.896h-4.923q-.401 0-.682-.294t-.281-.669v0q0-.401.281-.682t.682-.281h4.923v-4.896q0-.401.294-.682t.669-.281v0q.401 0 .682.281t.281.682v4.896h4.923q.401 0 .682.281t.281.682v0q0 .375-.281.669t-.682.294z" />
</SvgIcon>
Expand All @@ -27,7 +27,7 @@ function PlusSquare(props) {

function CloseSquare(props) {
return (
<SvgIcon className="close" fontSize="inherit" {...props}>
<SvgIcon className="close" fontSize="inherit" style={{ width: 14, height: 14 }} {...props}>
{/* tslint:disable-next-line: max-line-length */}
<path d="M17.485 17.512q-.281.281-.682.281t-.696-.268l-4.12-4.147-4.12 4.147q-.294.268-.696.268t-.682-.281-.281-.682.294-.669l4.12-4.147-4.12-4.147q-.294-.268-.294-.669t.281-.682.682-.281.696 .268l4.12 4.147 4.12-4.147q.294-.268.696-.268t.682.281 .281.669-.294.682l-4.12 4.147 4.12 4.147q.294.268 .294.669t-.281.682zM22.047 22.074v0 0-20.147 0h-20.12v0 20.147 0h20.12zM22.047 24h-20.12q-.803 0-1.365-.562t-.562-1.365v-20.147q0-.776.562-1.351t1.365-.575h20.147q.776 0 1.351.575t.575 1.351v20.147q0 .803-.575 1.365t-1.378.562v0z" />
</SvgIcon>
Expand Down Expand Up @@ -61,8 +61,8 @@ const StyledTreeItem = withStyles(theme => ({
},
},
group: {
marginLeft: 12,
paddingLeft: 12,
marginLeft: 7,
paddingLeft: 18,
borderLeft: `1px dashed ${fade(theme.palette.text.primary, 0.4)}`,
},
}))(props => <TreeItem {...props} TransitionComponent={TransitionComponent} />);
Expand Down
10 changes: 5 additions & 5 deletions docs/src/pages/components/tree-view/CustomizedTreeView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { TransitionProps } from '@material-ui/core/transitions';

function MinusSquare(props: SvgIconProps) {
return (
<SvgIcon fontSize="inherit" {...props}>
<SvgIcon fontSize="inherit" style={{ width: 14, height: 14 }} {...props}>
{/* tslint:disable-next-line: max-line-length */}
<path d="M22.047 22.074v0 0-20.147 0h-20.12v0 20.147 0h20.12zM22.047 24h-20.12q-.803 0-1.365-.562t-.562-1.365v-20.147q0-.776.562-1.351t1.365-.575h20.147q.776 0 1.351.575t.575 1.351v20.147q0 .803-.575 1.365t-1.378.562v0zM17.873 11.023h-11.826q-.375 0-.669.281t-.294.682v0q0 .401.294 .682t.669.281h11.826q.375 0 .669-.281t.294-.682v0q0-.401-.294-.682t-.669-.281z" />
</SvgIcon>
Expand All @@ -18,7 +18,7 @@ function MinusSquare(props: SvgIconProps) {

function PlusSquare(props: SvgIconProps) {
return (
<SvgIcon fontSize="inherit" {...props}>
<SvgIcon fontSize="inherit" style={{ width: 14, height: 14 }} {...props}>
{/* tslint:disable-next-line: max-line-length */}
<path d="M22.047 22.074v0 0-20.147 0h-20.12v0 20.147 0h20.12zM22.047 24h-20.12q-.803 0-1.365-.562t-.562-1.365v-20.147q0-.776.562-1.351t1.365-.575h20.147q.776 0 1.351.575t.575 1.351v20.147q0 .803-.575 1.365t-1.378.562v0zM17.873 12.977h-4.923v4.896q0 .401-.281.682t-.682.281v0q-.375 0-.669-.281t-.294-.682v-4.896h-4.923q-.401 0-.682-.294t-.281-.669v0q0-.401.281-.682t.682-.281h4.923v-4.896q0-.401.294-.682t.669-.281v0q.401 0 .682.281t.281.682v4.896h4.923q.401 0 .682.281t.281.682v0q0 .375-.281.669t-.682.294z" />
</SvgIcon>
Expand All @@ -27,7 +27,7 @@ function PlusSquare(props: SvgIconProps) {

function CloseSquare(props: SvgIconProps) {
return (
<SvgIcon className="close" fontSize="inherit" {...props}>
<SvgIcon className="close" fontSize="inherit" style={{ width: 14, height: 14 }} {...props}>
{/* tslint:disable-next-line: max-line-length */}
<path d="M17.485 17.512q-.281.281-.682.281t-.696-.268l-4.12-4.147-4.12 4.147q-.294.268-.696.268t-.682-.281-.281-.682.294-.669l4.12-4.147-4.12-4.147q-.294-.268-.294-.669t.281-.682.682-.281.696 .268l4.12 4.147 4.12-4.147q.294-.268.696-.268t.682.281 .281.669-.294.682l-4.12 4.147 4.12 4.147q.294.268 .294.669t-.281.682zM22.047 22.074v0 0-20.147 0h-20.12v0 20.147 0h20.12zM22.047 24h-20.12q-.803 0-1.365-.562t-.562-1.365v-20.147q0-.776.562-1.351t1.365-.575h20.147q.776 0 1.351.575t.575 1.351v20.147q0 .803-.575 1.365t-1.378.562v0z" />
</SvgIcon>
Expand Down Expand Up @@ -55,8 +55,8 @@ const StyledTreeItem = withStyles((theme: Theme) =>
},
},
group: {
marginLeft: 12,
paddingLeft: 12,
marginLeft: 7,
paddingLeft: 18,
borderLeft: `1px dashed ${fade(theme.palette.text.primary, 0.4)}`,
},
}),
Expand Down
3 changes: 2 additions & 1 deletion docs/src/pages/components/tree-view/FileSystemNavigator.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import TreeItem from '@material-ui/lab/TreeItem';

const useStyles = makeStyles({
root: {
height: 216,
height: 240,
flexGrow: 1,
maxWidth: 400,
},
Expand All @@ -28,6 +28,7 @@ export default function FileSystemNavigator() {
<TreeItem nodeId="4" label="Webstorm" />
</TreeItem>
<TreeItem nodeId="5" label="Documents">
<TreeItem nodeId="10" label="OSS" />
<TreeItem nodeId="6" label="Material-UI">
<TreeItem nodeId="7" label="src">
<TreeItem nodeId="8" label="index.js" />
Expand Down
3 changes: 2 additions & 1 deletion docs/src/pages/components/tree-view/FileSystemNavigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import TreeItem from '@material-ui/lab/TreeItem';

const useStyles = makeStyles({
root: {
height: 216,
height: 240,
flexGrow: 1,
maxWidth: 400,
},
Expand All @@ -28,6 +28,7 @@ export default function FileSystemNavigator() {
<TreeItem nodeId="4" label="Webstorm" />
</TreeItem>
<TreeItem nodeId="5" label="Documents">
<TreeItem nodeId="10" label="OSS" />
<TreeItem nodeId="6" label="Material-UI">
<TreeItem nodeId="7" label="src">
<TreeItem nodeId="8" label="index.js" />
Expand Down
10 changes: 9 additions & 1 deletion docs/src/pages/components/tree-view/GmailTreeView.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,16 @@ import ArrowRightIcon from '@material-ui/icons/ArrowRight';
const useTreeItemStyles = makeStyles(theme => ({
root: {
color: theme.palette.text.secondary,
'&:focus > $content': {
'&:hover > $content': {
backgroundColor: theme.palette.action.hover,
},
'&:focus > $content, &$selected > $content': {
backgroundColor: `var(--tree-view-bg-color, ${theme.palette.grey[400]})`,
color: 'var(--tree-view-color)',
},
'&:focus > $content $label, &:hover > $content $label, &$selected > $content $label': {
backgroundColor: 'transparent',
},
},
content: {
color: theme.palette.text.secondary,
Expand All @@ -39,6 +45,7 @@ const useTreeItemStyles = makeStyles(theme => ({
},
},
expanded: {},
selected: {},
label: {
fontWeight: 'inherit',
color: 'inherit',
Expand Down Expand Up @@ -82,6 +89,7 @@ function StyledTreeItem(props) {
root: classes.root,
content: classes.content,
expanded: classes.expanded,
selected: classes.selected,
group: classes.group,
label: classes.label,
}}
Expand Down
10 changes: 9 additions & 1 deletion docs/src/pages/components/tree-view/GmailTreeView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,16 @@ const useTreeItemStyles = makeStyles((theme: Theme) =>
createStyles({
root: {
color: theme.palette.text.secondary,
'&:focus > $content': {
'&:hover > $content': {
backgroundColor: theme.palette.action.hover,
},
'&:focus > $content, &$selected > $content': {
backgroundColor: `var(--tree-view-bg-color, ${theme.palette.grey[400]})`,
color: 'var(--tree-view-color)',
},
'&:focus > $content $label, &:hover > $content $label, &$selected > $content $label': {
backgroundColor: 'transparent',
},
},
content: {
color: theme.palette.text.secondary,
Expand All @@ -55,6 +61,7 @@ const useTreeItemStyles = makeStyles((theme: Theme) =>
},
},
expanded: {},
selected: {},
label: {
fontWeight: 'inherit',
color: 'inherit',
Expand Down Expand Up @@ -99,6 +106,7 @@ function StyledTreeItem(props: StyledTreeItemProps) {
root: classes.root,
content: classes.content,
expanded: classes.expanded,
selected: classes.selected,
group: classes.group,
label: classes.label,
}}
Expand Down
41 changes: 41 additions & 0 deletions docs/src/pages/components/tree-view/MultiSelectTreeView.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import TreeView from '@material-ui/lab/TreeView';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import ChevronRightIcon from '@material-ui/icons/ChevronRight';
import TreeItem from '@material-ui/lab/TreeItem';

const useStyles = makeStyles({
root: {
height: 216,
flexGrow: 1,
maxWidth: 400,
},
});

export default function MultiSelectTreeView() {
const classes = useStyles();

return (
<TreeView
className={classes.root}
defaultCollapseIcon={<ExpandMoreIcon />}
defaultExpandIcon={<ChevronRightIcon />}
multiSelect
>
<TreeItem nodeId="1" label="Applications">
<TreeItem nodeId="2" label="Calendar" />
<TreeItem nodeId="3" label="Chrome" />
<TreeItem nodeId="4" label="Webstorm" />
</TreeItem>
<TreeItem nodeId="5" label="Documents">
<TreeItem nodeId="6" label="Material-UI">
<TreeItem nodeId="7" label="src">
<TreeItem nodeId="8" label="index.js" />
<TreeItem nodeId="9" label="tree-view.js" />
</TreeItem>
</TreeItem>
</TreeItem>
</TreeView>
);
}
41 changes: 41 additions & 0 deletions docs/src/pages/components/tree-view/MultiSelectTreeView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import TreeView from '@material-ui/lab/TreeView';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import ChevronRightIcon from '@material-ui/icons/ChevronRight';
import TreeItem from '@material-ui/lab/TreeItem';

const useStyles = makeStyles({
root: {
height: 216,
flexGrow: 1,
maxWidth: 400,
},
});

export default function MultiSelectTreeView() {
const classes = useStyles();

return (
<TreeView
className={classes.root}
defaultCollapseIcon={<ExpandMoreIcon />}
defaultExpandIcon={<ChevronRightIcon />}
multiSelect
>
<TreeItem nodeId="1" label="Applications">
<TreeItem nodeId="2" label="Calendar" />
<TreeItem nodeId="3" label="Chrome" />
<TreeItem nodeId="4" label="Webstorm" />
</TreeItem>
<TreeItem nodeId="5" label="Documents">
<TreeItem nodeId="6" label="Material-UI">
<TreeItem nodeId="7" label="src">
<TreeItem nodeId="8" label="index.js" />
<TreeItem nodeId="9" label="tree-view.js" />
</TreeItem>
</TreeItem>
</TreeItem>
</TreeView>
);
}
10 changes: 9 additions & 1 deletion docs/src/pages/components/tree-view/tree-view.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,17 @@ components: TreeView, TreeItem

Tree views can be used to represent a file system navigator displaying folders and files, an item representing a folder can be expanded to reveal the contents of the folder, which may be files, folders, or both.

## Basic tree view

{{"demo": "pages/components/tree-view/FileSystemNavigator.js"}}

## Controlled
## Multi selection

Tree views also support multi selection.

{{"demo": "pages/components/tree-view/MultiSelectTreeView.js"}}

### Controlled tree view

The tree view also offers a controlled API.

Expand Down
1 change: 1 addition & 0 deletions packages/material-ui-lab/src/TreeItem/TreeItem.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export interface TreeItemProps
export type TreeItemClassKey =
| 'root'
| 'expanded'
| 'selected'
| 'group'
| 'content'
| 'iconContainer'
Expand Down
Loading

0 comments on commit 92c66df

Please sign in to comment.