Skip to content

Commit

Permalink
squashed changes
Browse files Browse the repository at this point in the history
  • Loading branch information
joshwooding committed Jul 3, 2020
1 parent 3645d20 commit 1ebc907
Show file tree
Hide file tree
Showing 7 changed files with 851 additions and 801 deletions.
2 changes: 2 additions & 0 deletions docs/pages/api-docs/tree-view.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ The `MuiTreeView` name can be used for providing [default props](/customization/
| <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">id</span> | <span class="prop-type">string</span> | | This prop is used to help implement the accessibility logic. If you don't provide this prop. It falls back to a randomly generated id. |
| <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">onNodeFocus</span> | <span class="prop-type">func</span> | | Callback fired when tree items are focused.<br><br>**Signature:**<br>`function(event: object, value: string) => void`<br>*event:* The event source of the callback<br>*value:* of the focused node. |
| <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: array \| string) => 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. |
Expand Down
190 changes: 16 additions & 174 deletions packages/material-ui-lab/src/TreeItem/TreeItem.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
/* eslint-disable jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */
import * as React from 'react';
import clsx from 'clsx';
import PropTypes from 'prop-types';
import Typography from '@material-ui/core/Typography';
import Collapse from '@material-ui/core/Collapse';
import { fade, withStyles, useTheme } from '@material-ui/core/styles';
import { fade, withStyles } from '@material-ui/core/styles';
import { useForkRef } from '@material-ui/core/utils';
import TreeViewContext from '../TreeView/TreeViewContext';
import { DescendantProvider, useDescendant, useDescendantsInit } from '../TreeView/descendants';
import { DescendantProvider, useDescendant } from '../TreeView/descendants';

export const styles = (theme) => ({
/* Styles applied to the root element. */
Expand Down Expand Up @@ -86,10 +85,6 @@ export const styles = (theme) => ({
},
});

const isPrintableCharacter = (str) => {
return str && str.length === 1 && str.match(/\S/);
};

const TreeItem = React.forwardRef(function TreeItem(props, ref) {
const {
children,
Expand All @@ -104,8 +99,6 @@ const TreeItem = React.forwardRef(function TreeItem(props, ref) {
onClick,
onLabelClick,
onIconClick,
onFocus,
onKeyDown,
onMouseDown,
TransitionComponent = Collapse,
TransitionProps,
Expand All @@ -115,29 +108,18 @@ const TreeItem = React.forwardRef(function TreeItem(props, ref) {
const {
icons: contextIcons,
focus,
focusFirstNode,
focusLastNode,
focusNextNode,
focusPreviousNode,
focusByFirstCharacter,
selectNode,
selectRange,
selectNextNode,
selectPreviousNode,
rangeSelectToFirst,
rangeSelectToLast,
selectAllNodes,
expandAllSiblings,
toggleExpansion,
isExpanded,
isFocused,
isSelected,
isTabbable,
multiSelect,
getParent,
mapFirstChar,
unMapFirstChar,
registerNode,
unregisterNode,
treeId,
} = React.useContext(TreeViewContext);

const nodeRef = React.useRef(null);
Expand All @@ -154,10 +136,8 @@ const TreeItem = React.forwardRef(function TreeItem(props, ref) {
const expandable = Boolean(Array.isArray(children) ? children.length : children);
const expanded = isExpanded ? isExpanded(nodeId) : false;
const focused = isFocused ? isFocused(nodeId) : false;
const tabbable = isTabbable ? isTabbable(nodeId) : false;
const selected = isSelected ? isSelected(nodeId) : false;
const icons = contextIcons || {};
const theme = useTheme();

if (!icon) {
if (expandable) {
Expand All @@ -177,7 +157,7 @@ const TreeItem = React.forwardRef(function TreeItem(props, ref) {

const handleClick = (event) => {
if (!focused) {
focus(nodeId);
focus(event, nodeId);
}

const multiple = multiSelect && (event.shiftKey || event.ctrlKey || event.metaKey);
Expand Down Expand Up @@ -213,135 +193,6 @@ const TreeItem = React.forwardRef(function TreeItem(props, ref) {
}
};

const handleNextArrow = (event) => {
if (expandable) {
if (expanded) {
focusNextNode(nodeId);
} else {
toggleExpansion(event);
}
}
return true;
};

const handlePreviousArrow = (event) => {
if (expanded) {
toggleExpansion(event, nodeId);
return true;
}

const parent = getParent(nodeId);
if (parent) {
focus(parent);
return true;
}
return false;
};

const handleKeyDown = (event) => {
let flag = false;
const key = event.key;

if (event.altKey || event.currentTarget !== event.target) {
return;
}

const ctrlPressed = event.ctrlKey || event.metaKey;

switch (key) {
case ' ':
if (nodeRef.current === event.currentTarget) {
if (multiSelect && event.shiftKey) {
flag = selectRange(event, { end: nodeId });
} else if (multiSelect) {
flag = selectNode(event, nodeId, true);
} else {
flag = selectNode(event, nodeId);
}
}
event.stopPropagation();
break;
case 'Enter':
if (nodeRef.current === event.currentTarget && expandable) {
toggleExpansion(event);
flag = true;
}
event.stopPropagation();
break;
case 'ArrowDown':
if (multiSelect && event.shiftKey) {
selectNextNode(event, nodeId);
}
focusNextNode(nodeId);
flag = true;
break;
case 'ArrowUp':
if (multiSelect && event.shiftKey) {
selectPreviousNode(event, nodeId);
}
focusPreviousNode(nodeId);
flag = true;
break;
case 'ArrowRight':
if (theme.direction === 'rtl') {
flag = handlePreviousArrow(event);
} else {
flag = handleNextArrow(event);
}
break;
case 'ArrowLeft':
if (theme.direction === 'rtl') {
flag = handleNextArrow(event);
} else {
flag = handlePreviousArrow(event);
}
break;
case 'Home':
if (multiSelect && ctrlPressed && event.shiftKey) {
rangeSelectToFirst(event, nodeId);
}
focusFirstNode();
flag = true;
break;
case 'End':
if (multiSelect && ctrlPressed && event.shiftKey) {
rangeSelectToLast(event, nodeId);
}
focusLastNode();
flag = true;
break;
default:
if (key === '*') {
expandAllSiblings(event, nodeId);
flag = true;
} else if (multiSelect && ctrlPressed && key.toLowerCase() === 'a') {
flag = selectAllNodes(event);
} else if (!ctrlPressed && !event.shiftKey && isPrintableCharacter(key)) {
focusByFirstCharacter(nodeId, key);
flag = true;
}
}

if (flag) {
event.preventDefault();
event.stopPropagation();
}

if (onKeyDown) {
onKeyDown(event);
}
};

const handleFocus = (event) => {
if (!focused && event.currentTarget === event.target) {
focus(nodeId);
}

if (onFocus) {
onFocus(event);
}
};

React.useEffect(() => {
// On the first render a node's index will be -1. We want to wait for the real index.
if (registerNode && unregisterNode && index !== -1) {
Expand All @@ -363,14 +214,13 @@ const TreeItem = React.forwardRef(function TreeItem(props, ref) {
React.useEffect(() => {
if (mapFirstChar && label) {
mapFirstChar(nodeId, contentRef.current.textContent.substring(0, 1).toLowerCase());
}
}, [mapFirstChar, nodeId, label]);

React.useEffect(() => {
if (focused) {
nodeRef.current.focus();
return () => {
unMapFirstChar(nodeId);
};
}
}, [focused]);
return undefined;
}, [mapFirstChar, unMapFirstChar, nodeId, label]);

let ariaSelected;
if (multiSelect) {
Expand All @@ -385,20 +235,18 @@ const TreeItem = React.forwardRef(function TreeItem(props, ref) {
ariaSelected = true;
}

const [descendants, setDescendants] = useDescendantsInit();

return (
<li
className={clsx(classes.root, className)}
role="treeitem"
onKeyDown={handleKeyDown}
onFocus={handleFocus}
aria-expanded={expandable ? expanded : null}
aria-selected={ariaSelected}
ref={handleRef}
tabIndex={tabbable ? 0 : -1}
id={`${treeId}-${nodeId}`}
{...other}
>
{/* Key event is handled by the TreeView */}
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
<div
className={clsx(classes.content, {
[classes.expanded]: expanded,
Expand All @@ -409,6 +257,8 @@ const TreeItem = React.forwardRef(function TreeItem(props, ref) {
onMouseDown={handleMouseDown}
ref={contentRef}
>
{/* Key event is handled by the TreeView */}
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
<div onClick={onIconClick} className={classes.iconContainer}>
{icon}
</div>
Expand All @@ -417,7 +267,7 @@ const TreeItem = React.forwardRef(function TreeItem(props, ref) {
</Typography>
</div>
{children && (
<DescendantProvider items={descendants} set={setDescendants} id={nodeId}>
<DescendantProvider id={nodeId}>
<TransitionComponent
unmountOnExit
className={classes.group}
Expand Down Expand Up @@ -480,18 +330,10 @@ TreeItem.propTypes = {
* @ignore
*/
onClick: PropTypes.func,
/**
* @ignore
*/
onFocus: PropTypes.func,
/**
* `onClick` handler for the icon container. Call `event.preventDefault()` to prevent `onNodeToggle` from being called.
*/
onIconClick: PropTypes.func,
/**
* @ignore
*/
onKeyDown: PropTypes.func,
/**
* `onClick` handler for the label container. Call `event.preventDefault()` to prevent `onNodeToggle` from being called.
*/
Expand Down
Loading

0 comments on commit 1ebc907

Please sign in to comment.