@salesforce/design-system-react
Version:
Salesforce Lightning Design System for React
319 lines (277 loc) • 10.6 kB
JavaScript
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
/* Copyright (c) 2015-present, salesforce.com, inc. All rights reserved */
/* Licensed under BSD 3-Clause - see LICENSE.txt or git.io/sfdc-license */
// # Tree Item Component
// Implements the [Tree design pattern](https://www.lightningdesignsystem.com/components/tree/) in React.
// ### React
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import findIndex from 'lodash.findindex';
import isFunction from 'lodash.isfunction';
import Button from '../../button';
import Highlighter from '../../utilities/highlighter';
import EventUtil from '../../../utilities/event';
import KEYS from '../../../utilities/key-code';
import mapKeyEventCallbacks from '../../../utilities/key-callbacks';
import { TREE_ITEM } from '../../../utilities/constants';
var handleSelect = function handleSelect(_ref) {
var event = _ref.event,
props = _ref.props,
fromFocus = _ref.fromFocus;
EventUtil.trap(event);
if (isFunction(props.onSelect)) {
props.onSelect({
event: event,
data: {
node: props.node,
select: !props.node.selected,
treeIndex: props.treeIndex
},
fromFocus: fromFocus
});
}
};
var findNextNode = function findNextNode(flattenedNodes, node) {
var nodes = flattenedNodes.map(function (flattenedNode) {
return flattenedNode.node;
});
var index = findIndex(nodes, {
id: node.id
});
return flattenedNodes[(index + 1) % flattenedNodes.length];
};
var findPreviousNode = function findPreviousNode(flattenedNodes, node) {
var nodes = flattenedNodes.map(function (flattenedNode) {
return flattenedNode.node;
});
var index = findIndex(nodes, {
id: node.id
}) - 1;
if (index < 0) {
index += flattenedNodes.length;
}
return flattenedNodes[index];
};
var handleKeyDownDown = function handleKeyDownDown(event, props) {
if (props.focusedNodeIndex === props.treeIndex) {
// Select the next visible node
var flattenedNode = findNextNode(props.flattenedNodes, props.node);
props.onSelect({
event: event,
data: {
node: flattenedNode.node,
select: true,
treeIndex: flattenedNode.treeIndex
},
clearSelectedNodes: true
});
}
};
var handleKeyDownUp = function handleKeyDownUp(event, props) {
if (props.focusedNodeIndex === props.treeIndex) {
// Go to the previous visible node
var flattenedNode = findPreviousNode(props.flattenedNodes, props.node);
props.onSelect({
event: event,
data: {
node: flattenedNode.node,
select: true,
treeIndex: flattenedNode.treeIndex
},
clearSelectedNodes: true
});
}
};
var handleKeyDownLeft = function handleKeyDownLeft(event, props) {
var nodes = props.flattenedNodes.map(function (flattenedNode) {
return flattenedNode.node;
});
var index = findIndex(nodes, {
id: props.parent.id
});
if (index !== -1) {
props.onExpand({
event: event,
data: {
node: props.parent,
select: true,
expand: !props.parent.expanded,
treeIndex: props.flattenedNodes[index].treeIndex
}
});
}
};
var handleKeyDownEnter = function handleKeyDownEnter(event, props) {
handleSelect({
event: event,
props: props
});
};
var handleKeyDown = function handleKeyDown(event, props) {
var _callbacks;
mapKeyEventCallbacks(event, {
callbacks: (_callbacks = {}, _defineProperty(_callbacks, KEYS.DOWN, {
callback: function callback(evt) {
return handleKeyDownDown(evt, props);
}
}), _defineProperty(_callbacks, KEYS.UP, {
callback: function callback(evt) {
return handleKeyDownUp(evt, props);
}
}), _defineProperty(_callbacks, KEYS.LEFT, {
callback: function callback(evt) {
return handleKeyDownLeft(evt, props);
}
}), _defineProperty(_callbacks, KEYS.ENTER, {
callback: function callback(evt) {
return handleKeyDownEnter(evt, props);
}
}), _callbacks)
});
};
var handleFocus = function handleFocus(event, props) {
if (!props.treeHasFocus && !props.focusedNodeIndex && event.target === event.currentTarget) {
handleSelect({
event: event,
props: props
});
}
};
var getTabIndex = function getTabIndex(props) {
var initialFocus = props.selectedNodeIndexes.length === 0 && props.treeIndex === props.flattenedNodes[0].treeIndex;
return props.treeIndex === props.focusedNodeIndex || initialFocus ? 0 : -1;
};
/**
* A Tree Item is a non-branching node in a hierarchical list.
*/
var Item = function Item(_ref2) {
var _ref2$selected = _ref2.selected,
selected = _ref2$selected === void 0 ? false : _ref2$selected,
_ref2$selectedNodeInd = _ref2.selectedNodeIndexes,
selectedNodeIndexes = _ref2$selectedNodeInd === void 0 ? [] : _ref2$selectedNodeInd,
rest = _objectWithoutProperties(_ref2, ["selected", "selectedNodeIndexes"]);
var props = _objectSpread({
selected: selected,
selectedNodeIndexes: selectedNodeIndexes
}, rest);
var isSelected = props.node.selected;
var isFocused = props.treeIndex === props.focusedNodeIndex;
return /*#__PURE__*/React.createElement("li", {
id: "".concat(props.treeId, "-").concat(props.node.id),
role: "treeitem",
"aria-level": props.level,
"aria-selected": isSelected ? 'true' : 'false',
tabIndex: getTabIndex(props),
onKeyDown: function onKeyDown(event) {
return handleKeyDown(event, props);
},
onFocus: function onFocus(event) {
return handleFocus(event, props);
},
onBlur: props.onNodeBlur,
ref: function ref(component) {
if (props.treeHasFocus && component && isFocused) {
component.focus();
}
}
}, /*#__PURE__*/React.createElement("div", {
className: classNames('slds-tree__item', {
'slds-is-selected': isSelected
}),
onClick: function onClick(event) {
handleSelect({
event: event,
props: props
});
}
}, /*#__PURE__*/React.createElement(Button, {
tabIndex: "-1",
"aria-hidden": true,
assistiveText: {
icon: ''
},
role: "presentation",
iconCategory: "utility",
iconName: "chevronright",
iconSize: "small",
variant: "icon",
className: "slds-m-right_small slds-is-disabled",
disabled: true
}), /*#__PURE__*/React.createElement("span", {
className: "slds-size_1-of-1"
}, /*#__PURE__*/React.createElement(Highlighter, {
search: props.searchTerm,
className: "slds-tree__item-label slds-truncate"
}, props.label))));
}; // ### Display Name
// Always use the canonical component name as the React display name.
Item.displayName = TREE_ITEM; // ### Prop Types
Item.propTypes = {
/**
* HTML `id` of the wrapping container element joined with the `id` of the node. This will recursively increase as the tree depth increases.
*/
htmlId: PropTypes.string.isRequired,
/**
* The text of the tree item.
*/
label: PropTypes.oneOfType([PropTypes.node, PropTypes.string]).isRequired,
/**
* The number of nestings. Determines the ARIA level and style alignment.
*/
level: PropTypes.number.isRequired,
/**
* The current node that is being rendered.
*/
node: PropTypes.object.isRequired,
/**
* This function triggers when the expand or collapse icon is clicked or due to keyboard navigation.
*/
onExpand: PropTypes.func.isRequired,
/**
* Function that will run whenever an item or branch is selected (click or keyboard).
*/
onSelect: PropTypes.func,
/**
* Highlights term if found in node label
*/
searchTerm: PropTypes.string,
/**
* Unique id used for a prefix of all tree nodes
*/
treeId: PropTypes.string,
/**
* Location of node (zero index). First node is `0`. It's first child is `0-0`. This can be used to modify your nodes without searching for the node. This index is only valid if the `nodes` prop is the same as at the time of the event.
*/
treeIndex: PropTypes.string,
/**
* Flattened tree structure.
*/
flattenedNodes: PropTypes.arrayOf(PropTypes.object),
/**
* Tree indexes of nodes that are currently selected.
*/
selectedNodeIndexes: PropTypes.arrayOf(PropTypes.string),
/**
* Tree index of the node that is currently focused.
*/
focusedNodeIndex: PropTypes.string,
/**
* Callback for when a node is blurred.
*/
onNodeBlur: PropTypes.func,
/**
* Sets focus on render.
*/
treeHasFocus: PropTypes.bool,
/**
* This node's parent.
*/
parent: PropTypes.object
};
export default Item;
//# sourceMappingURL=item.js.map