UNPKG

@material-ui/lab

Version:

Material-UI Lab - Incubator for Material-UI React components.

543 lines (455 loc) 15.4 kB
"use strict"; var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard"); var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = exports.styles = void 0; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties")); var React = _interopRequireWildcard(require("react")); var _clsx = _interopRequireDefault(require("clsx")); var _propTypes = _interopRequireDefault(require("prop-types")); var _Typography = _interopRequireDefault(require("@material-ui/core/Typography")); var _Collapse = _interopRequireDefault(require("@material-ui/core/Collapse")); var _styles = require("@material-ui/core/styles"); var _utils = require("@material-ui/core/utils"); var _TreeViewContext = _interopRequireDefault(require("../TreeView/TreeViewContext")); /* eslint-disable jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */ var styles = function styles(theme) { return { /* Styles applied to the root element. */ root: { listStyle: 'none', margin: 0, padding: 0, outline: 0, WebkitTapHighlightColor: 'transparent', '&:focus > $content $label': { backgroundColor: theme.palette.action.hover }, '&$selected > $content $label': { backgroundColor: (0, _styles.alpha)(theme.palette.primary.main, theme.palette.action.selectedOpacity) }, '&$selected > $content $label:hover, &$selected:focus > $content $label': { backgroundColor: (0, _styles.alpha)(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, padding: 0, marginLeft: 17 }, /* Styles applied to the tree node content. */ content: { width: '100%', display: 'flex', alignItems: 'center', cursor: 'pointer' }, /* Styles applied to the tree node icon and collapse/expand icon. */ iconContainer: { marginRight: 4, width: 15, display: 'flex', flexShrink: 0, justifyContent: 'center', '& svg': { fontSize: 18 } }, /* Styles applied to the label element. */ label: { 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' } } } }; }; exports.styles = styles; var isPrintableCharacter = function isPrintableCharacter(str) { return str && str.length === 1 && str.match(/\S/); }; var TreeItem = /*#__PURE__*/React.forwardRef(function TreeItem(props, ref) { var children = props.children, classes = props.classes, className = props.className, collapseIcon = props.collapseIcon, endIcon = props.endIcon, expandIcon = props.expandIcon, iconProp = props.icon, label = props.label, nodeId = props.nodeId, onClick = props.onClick, onLabelClick = props.onLabelClick, onIconClick = props.onIconClick, onFocus = props.onFocus, onKeyDown = props.onKeyDown, onMouseDown = props.onMouseDown, _props$TransitionComp = props.TransitionComponent, TransitionComponent = _props$TransitionComp === void 0 ? _Collapse.default : _props$TransitionComp, TransitionProps = props.TransitionProps, other = (0, _objectWithoutProperties2.default)(props, ["children", "classes", "className", "collapseIcon", "endIcon", "expandIcon", "icon", "label", "nodeId", "onClick", "onLabelClick", "onIconClick", "onFocus", "onKeyDown", "onMouseDown", "TransitionComponent", "TransitionProps"]); var _React$useContext = React.useContext(_TreeViewContext.default), contextIcons = _React$useContext.icons, focus = _React$useContext.focus, focusFirstNode = _React$useContext.focusFirstNode, focusLastNode = _React$useContext.focusLastNode, focusNextNode = _React$useContext.focusNextNode, focusPreviousNode = _React$useContext.focusPreviousNode, focusByFirstCharacter = _React$useContext.focusByFirstCharacter, selectNode = _React$useContext.selectNode, selectRange = _React$useContext.selectRange, selectNextNode = _React$useContext.selectNextNode, selectPreviousNode = _React$useContext.selectPreviousNode, rangeSelectToFirst = _React$useContext.rangeSelectToFirst, rangeSelectToLast = _React$useContext.rangeSelectToLast, selectAllNodes = _React$useContext.selectAllNodes, expandAllSiblings = _React$useContext.expandAllSiblings, toggleExpansion = _React$useContext.toggleExpansion, isExpanded = _React$useContext.isExpanded, isFocused = _React$useContext.isFocused, isSelected = _React$useContext.isSelected, isTabbable = _React$useContext.isTabbable, multiSelect = _React$useContext.multiSelect, getParent = _React$useContext.getParent, mapFirstChar = _React$useContext.mapFirstChar, addNodeToNodeMap = _React$useContext.addNodeToNodeMap, removeNodeFromNodeMap = _React$useContext.removeNodeFromNodeMap; var nodeRef = React.useRef(null); var contentRef = React.useRef(null); var handleRef = (0, _utils.useForkRef)(nodeRef, ref); var icon = iconProp; var expandable = Boolean(Array.isArray(children) ? children.length : children); var expanded = isExpanded ? isExpanded(nodeId) : false; var focused = isFocused ? isFocused(nodeId) : false; var tabbable = isTabbable ? isTabbable(nodeId) : false; var selected = isSelected ? isSelected(nodeId) : false; var icons = contextIcons || {}; var theme = (0, _styles.useTheme)(); if (!icon) { if (expandable) { if (!expanded) { icon = expandIcon || icons.defaultExpandIcon; } else { icon = collapseIcon || icons.defaultCollapseIcon; } if (!icon) { icon = icons.defaultParentIcon; } } else { icon = endIcon || icons.defaultEndIcon; } } var handleClick = function handleClick(event) { if (!focused) { focus(nodeId); } var multiple = multiSelect && (event.shiftKey || event.ctrlKey || event.metaKey); // If already expanded and trying to toggle selection don't close if (expandable && !event.defaultPrevented && !(multiple && isExpanded(nodeId))) { toggleExpansion(event, nodeId); } if (multiple) { if (event.shiftKey) { selectRange(event, { end: nodeId }); } else { selectNode(event, nodeId, true); } } else { selectNode(event, nodeId); } if (onClick) { onClick(event); } }; var handleMouseDown = function handleMouseDown(event) { if (event.shiftKey || event.ctrlKey || event.metaKey) { event.preventDefault(); } if (onMouseDown) { onMouseDown(event); } }; var handleNextArrow = function handleNextArrow(event) { if (expandable) { if (expanded) { focusNextNode(nodeId); } else { toggleExpansion(event); } } return true; }; var handlePreviousArrow = function handlePreviousArrow(event) { if (expanded) { toggleExpansion(event, nodeId); return true; } var parent = getParent(nodeId); if (parent) { focus(parent); return true; } return false; }; var handleKeyDown = function handleKeyDown(event) { var flag = false; var key = event.key; if (event.altKey || event.currentTarget !== event.target) { return; } var 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); } }; var handleFocus = function handleFocus(event) { if (!focused && event.currentTarget === event.target) { focus(nodeId); } if (onFocus) { onFocus(event); } }; React.useEffect(function () { if (addNodeToNodeMap) { var childIds = []; React.Children.forEach(children, function (child) { if ( /*#__PURE__*/React.isValidElement(child) && child.props.nodeId) { childIds.push(child.props.nodeId); } }); addNodeToNodeMap(nodeId, childIds); } }, [children, nodeId, addNodeToNodeMap]); React.useEffect(function () { if (removeNodeFromNodeMap) { return function () { removeNodeFromNodeMap(nodeId); }; } return undefined; }, [nodeId, removeNodeFromNodeMap]); React.useEffect(function () { if (mapFirstChar && label) { mapFirstChar(nodeId, contentRef.current.textContent.substring(0, 1).toLowerCase()); } }, [mapFirstChar, nodeId, label]); React.useEffect(function () { if (focused) { nodeRef.current.focus(); } }, [focused]); var ariaSelected; if (multiSelect) { ariaSelected = selected; } else if (selected) { // single-selection trees unset aria-selected ariaSelected = true; } return /*#__PURE__*/React.createElement("li", (0, _extends2.default)({ className: (0, _clsx.default)(classes.root, className, expanded && classes.expanded, selected && classes.selected), role: "treeitem", onKeyDown: handleKeyDown, onFocus: handleFocus, "aria-expanded": expandable ? expanded : null, "aria-selected": ariaSelected, ref: handleRef, tabIndex: tabbable ? 0 : -1 }, other), /*#__PURE__*/React.createElement("div", { className: classes.content, onClick: handleClick, onMouseDown: handleMouseDown, ref: contentRef }, /*#__PURE__*/React.createElement("div", { onClick: onIconClick, className: classes.iconContainer }, icon), /*#__PURE__*/React.createElement(_Typography.default, { onClick: onLabelClick, component: "div", className: classes.label }, label)), children && /*#__PURE__*/React.createElement(TransitionComponent, (0, _extends2.default)({ unmountOnExit: true, className: classes.group, in: expanded, component: "ul", role: "group" }, TransitionProps), children)); }); process.env.NODE_ENV !== "production" ? TreeItem.propTypes = { // ----------------------------- Warning -------------------------------- // | These PropTypes are generated from the TypeScript type definitions | // | To update them edit the d.ts file and run "yarn proptypes" | // ---------------------------------------------------------------------- /** * The content of the component. */ children: _propTypes.default.node, /** * Override or extend the styles applied to the component. * See [CSS API](#css) below for more details. */ classes: _propTypes.default.object, /** * @ignore */ className: _propTypes.default.string, /** * The icon used to collapse the node. */ collapseIcon: _propTypes.default.node, /** * The icon displayed next to a end node. */ endIcon: _propTypes.default.node, /** * The icon used to expand the node. */ expandIcon: _propTypes.default.node, /** * The icon to display next to the tree node's label. */ icon: _propTypes.default.node, /** * The tree node label. */ label: _propTypes.default.node, /** * The id of the node. */ nodeId: _propTypes.default.string.isRequired, /** * @ignore */ onClick: _propTypes.default.func, /** * @ignore */ onFocus: _propTypes.default.func, /** * `onClick` handler for the icon container. Call `event.preventDefault()` to prevent `onNodeToggle` from being called. */ onIconClick: _propTypes.default.func, /** * @ignore */ onKeyDown: _propTypes.default.func, /** * `onClick` handler for the label container. Call `event.preventDefault()` to prevent `onNodeToggle` from being called. */ onLabelClick: _propTypes.default.func, /** * @ignore */ onMouseDown: _propTypes.default.func, /** * The component used for the transition. * [Follow this guide](/components/transitions/#transitioncomponent-prop) to learn more about the requirements for this component. */ TransitionComponent: _propTypes.default.elementType, /** * Props applied to the [`Transition`](http://reactcommunity.org/react-transition-group/transition#Transition-props) element. */ TransitionProps: _propTypes.default.object } : void 0; var _default = (0, _styles.withStyles)(styles, { name: 'MuiTreeItem' })(TreeItem); exports.default = _default;