diff --git a/docs/pages/api-docs/tree-item.md b/docs/pages/api-docs/tree-item.md index 69ac352d35e1d7..07764b0d7157a1 100644 --- a/docs/pages/api-docs/tree-item.md +++ b/docs/pages/api-docs/tree-item.md @@ -50,10 +50,11 @@ Any other props supplied will be provided to the root element (native element). | Rule name | Global class | Description | |:-----|:-------------|:------------| | root | .MuiTreeItem-root | Styles applied to the root element. -| expanded | .Mui-expanded | Pseudo-class applied to the root element when expanded. -| selected | .Mui-selected | Pseudo-class applied to the root element when selected. | group | .MuiTreeItem-group | Styles applied to the `role="group"` element. | content | .MuiTreeItem-content | Styles applied to the tree node content. +| expanded | .Mui-expanded | Pseudo-class applied to the content element when expanded. +| selected | .Mui-selected | Pseudo-class applied to the content element when selected. +| focused | .Mui-focused | Pseudo-class applied to the content element when focused. | iconContainer | .MuiTreeItem-iconContainer | Styles applied to the tree node icon and collapse/expand icon. | label | .MuiTreeItem-label | Styles applied to the label element. diff --git a/docs/src/pages/components/tree-view/GmailTreeView.js b/docs/src/pages/components/tree-view/GmailTreeView.js index c789a46d516762..bc5ec2774e0491 100644 --- a/docs/src/pages/components/tree-view/GmailTreeView.js +++ b/docs/src/pages/components/tree-view/GmailTreeView.js @@ -17,16 +17,6 @@ import ArrowRightIcon from '@material-ui/icons/ArrowRight'; const useTreeItemStyles = makeStyles((theme) => ({ root: { color: theme.palette.text.secondary, - '&: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, @@ -34,9 +24,16 @@ const useTreeItemStyles = makeStyles((theme) => ({ borderBottomRightRadius: theme.spacing(2), paddingRight: theme.spacing(1), fontWeight: theme.typography.fontWeightMedium, - '$expanded > &': { + '&$expanded': { fontWeight: theme.typography.fontWeightRegular, }, + '&:hover': { + backgroundColor: theme.palette.action.hover, + }, + '&$focused, &$selected, &$selected$focused': { + backgroundColor: `var(--tree-view-bg-color, ${theme.palette.action.selected})`, + color: 'var(--tree-view-color)', + }, }, group: { marginLeft: 0, @@ -46,6 +43,7 @@ const useTreeItemStyles = makeStyles((theme) => ({ }, expanded: {}, selected: {}, + focused: {}, label: { fontWeight: 'inherit', color: 'inherit', @@ -53,7 +51,7 @@ const useTreeItemStyles = makeStyles((theme) => ({ labelRoot: { display: 'flex', alignItems: 'center', - padding: theme.spacing(0.5, 0), + padding: theme.spacing(0.5, 0, 0.5, 0.5), }, labelIcon: { marginRight: theme.spacing(1), @@ -67,11 +65,11 @@ const useTreeItemStyles = makeStyles((theme) => ({ function StyledTreeItem(props) { const classes = useTreeItemStyles(); const { - labelText, + bgColor, + color, labelIcon: LabelIcon, labelInfo, - color, - bgColor, + labelText, ...other } = props; @@ -97,6 +95,7 @@ function StyledTreeItem(props) { content: classes.content, expanded: classes.expanded, selected: classes.selected, + focused: classes.focused, group: classes.group, label: classes.label, }} diff --git a/docs/src/pages/components/tree-view/GmailTreeView.tsx b/docs/src/pages/components/tree-view/GmailTreeView.tsx index 626e386080b432..0dba1910ecbfca 100644 --- a/docs/src/pages/components/tree-view/GmailTreeView.tsx +++ b/docs/src/pages/components/tree-view/GmailTreeView.tsx @@ -33,16 +33,6 @@ const useTreeItemStyles = makeStyles((theme: Theme) => createStyles({ root: { color: theme.palette.text.secondary, - '&: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, @@ -50,9 +40,16 @@ const useTreeItemStyles = makeStyles((theme: Theme) => borderBottomRightRadius: theme.spacing(2), paddingRight: theme.spacing(1), fontWeight: theme.typography.fontWeightMedium, - '$expanded > &': { + '&$expanded': { fontWeight: theme.typography.fontWeightRegular, }, + '&:hover': { + backgroundColor: theme.palette.action.hover, + }, + '&$focused, &$selected, &$selected$focused': { + backgroundColor: `var(--tree-view-bg-color, ${theme.palette.action.selected})`, + color: 'var(--tree-view-color)', + }, }, group: { marginLeft: 0, @@ -62,6 +59,7 @@ const useTreeItemStyles = makeStyles((theme: Theme) => }, expanded: {}, selected: {}, + focused: {}, label: { fontWeight: 'inherit', color: 'inherit', @@ -69,7 +67,7 @@ const useTreeItemStyles = makeStyles((theme: Theme) => labelRoot: { display: 'flex', alignItems: 'center', - padding: theme.spacing(0.5, 0), + padding: theme.spacing(0.5, 0, 0.5, 0.5), }, labelIcon: { marginRight: theme.spacing(1), @@ -84,11 +82,11 @@ const useTreeItemStyles = makeStyles((theme: Theme) => function StyledTreeItem(props: StyledTreeItemProps) { const classes = useTreeItemStyles(); const { - labelText, + bgColor, + color, labelIcon: LabelIcon, labelInfo, - color, - bgColor, + labelText, ...other } = props; @@ -114,6 +112,7 @@ function StyledTreeItem(props: StyledTreeItemProps) { content: classes.content, expanded: classes.expanded, selected: classes.selected, + focused: classes.focused, group: classes.group, label: classes.label, }} diff --git a/packages/material-ui-lab/src/PaginationItem/PaginationItem.js b/packages/material-ui-lab/src/PaginationItem/PaginationItem.js index 7133b5362392c2..bf91b0720d3aaa 100644 --- a/packages/material-ui-lab/src/PaginationItem/PaginationItem.js +++ b/packages/material-ui-lab/src/PaginationItem/PaginationItem.js @@ -39,7 +39,7 @@ export const styles = (theme) => ({ }, '&$selected': { backgroundColor: theme.palette.action.selected, - '&:hover, &$focusVisible': { + '&:hover': { backgroundColor: fade( theme.palette.action.selected, theme.palette.action.selectedOpacity + theme.palette.action.hoverOpacity, @@ -49,6 +49,12 @@ export const styles = (theme) => ({ backgroundColor: theme.palette.action.selected, }, }, + '&$focusVisible': { + backgroundColor: fade( + theme.palette.action.selected, + theme.palette.action.selectedOpacity + theme.palette.action.focusOpacity, + ), + }, '&$disabled': { opacity: 1, color: theme.palette.action.disabled, @@ -135,7 +141,7 @@ export const styles = (theme) => ({ '&:hover, &$focusVisible': { backgroundColor: fade( theme.palette.primary.main, - theme.palette.action.activatedOpacity + theme.palette.action.hoverOpacity, + theme.palette.action.activatedOpacity + theme.palette.action.focusOpacity, ), // Reset on touch devices, it doesn't add specificity '@media (hover: none)': { @@ -156,7 +162,7 @@ export const styles = (theme) => ({ '&:hover, &$focusVisible': { backgroundColor: fade( theme.palette.secondary.main, - theme.palette.action.activatedOpacity + theme.palette.action.hoverOpacity, + theme.palette.action.activatedOpacity + theme.palette.action.focusOpacity, ), // Reset on touch devices, it doesn't add specificity '@media (hover: none)': { diff --git a/packages/material-ui-lab/src/TreeItem/TreeItem.d.ts b/packages/material-ui-lab/src/TreeItem/TreeItem.d.ts index aff614ab7ddbbb..5d57784f47d147 100644 --- a/packages/material-ui-lab/src/TreeItem/TreeItem.d.ts +++ b/packages/material-ui-lab/src/TreeItem/TreeItem.d.ts @@ -55,6 +55,7 @@ export type TreeItemClassKey = | 'root' | 'expanded' | 'selected' + | 'focused' | 'group' | 'content' | 'iconContainer' diff --git a/packages/material-ui-lab/src/TreeItem/TreeItem.js b/packages/material-ui-lab/src/TreeItem/TreeItem.js index 149db4c81ede70..8b8fa806a2b9da 100644 --- a/packages/material-ui-lab/src/TreeItem/TreeItem.js +++ b/packages/material-ui-lab/src/TreeItem/TreeItem.js @@ -15,28 +15,7 @@ export const styles = (theme) => ({ margin: 0, padding: 0, outline: 0, - WebkitTapHighlightColor: 'transparent', - '&:focus > $content $label': { - backgroundColor: theme.palette.action.hover, - }, - '&$selected > $content $label': { - backgroundColor: fade(theme.palette.primary.main, theme.palette.action.selectedOpacity), - }, - '&$selected > $content $label:hover, &$selected:focus > $content $label': { - backgroundColor: fade( - theme.palette.primary.main, - theme.palette.action.selectedOpacity + theme.palette.action.hoverOpacity, - ), - // Reset on touch devices, it doesn't add specificity - '@media (hover: none)': { - backgroundColor: 'transparent', - }, - }, }, - /* Pseudo-class applied to the root element when expanded. */ - expanded: {}, - /* Pseudo-class applied to the root element when selected. */ - selected: {}, /* Styles applied to the `role="group"` element. */ group: { margin: 0, @@ -49,7 +28,43 @@ export const styles = (theme) => ({ display: 'flex', alignItems: 'center', cursor: 'pointer', + WebkitTapHighlightColor: 'transparent', + '&:hover': { + backgroundColor: theme.palette.action.hover, + // Reset on touch devices, it doesn't add specificity + '@media (hover: none)': { + backgroundColor: 'transparent', + }, + }, + '&$focused': { + backgroundColor: theme.palette.action.focus, + }, + '&$selected': { + backgroundColor: fade(theme.palette.primary.main, theme.palette.action.selectedOpacity), + '&:hover': { + backgroundColor: fade( + theme.palette.primary.main, + theme.palette.action.selectedOpacity + theme.palette.action.hoverOpacity, + ), + // Reset on touch devices, it doesn't add specificity + '@media (hover: none)': { + backgroundColor: fade(theme.palette.primary.main, theme.palette.action.selectedOpacity), + }, + }, + '&$focused': { + backgroundColor: fade( + theme.palette.primary.main, + theme.palette.action.selectedOpacity + theme.palette.action.focusOpacity, + ), + }, + }, }, + /* Pseudo-class applied to the content element when expanded. */ + expanded: {}, + /* Pseudo-class applied to the content element when selected. */ + selected: {}, + /* Pseudo-class applied to the content element when focused. */ + focused: {}, /* Styles applied to the tree node icon and collapse/expand icon. */ iconContainer: { marginRight: 4, @@ -66,13 +81,6 @@ export const styles = (theme) => ({ width: '100%', paddingLeft: 4, position: 'relative', - '&:hover': { - backgroundColor: theme.palette.action.hover, - // Reset on touch devices, it doesn't add specificity - '@media (hover: none)': { - backgroundColor: 'transparent', - }, - }, }, }); @@ -189,6 +197,7 @@ const TreeItem = React.forwardRef(function TreeItem(props, ref) { const handleMouseDown = (event) => { if (event.shiftKey || event.ctrlKey || event.metaKey) { + // Prevent text selection event.preventDefault(); } @@ -363,16 +372,18 @@ const TreeItem = React.forwardRef(function TreeItem(props, ref) { if (multiSelect) { ariaSelected = selected; } else if (selected) { - // single-selection trees unset aria-selected + /* single-selection trees unset aria-selected on un-selected items. + * + * If the tree does not support multiple selection, aria-selected + * is set to true for the selected node and it is not present on any other node in the tree. + * Source: https://www.w3.org/TR/wai-aria-practices/#TreeView + */ ariaSelected = true; } return (
  • ', () => { fireEvent.keyDown(getByTestId('one'), { key: ' ' }); expect(getByTestId('one')).to.have.attribute('aria-selected', 'true'); - expect(getByTestId('one')).to.have.class('Mui-selected'); }); it('should not select a node when space is pressed and disableSelection', () => {