rsuite
Version:
A suite of react components
304 lines (301 loc) • 12.3 kB
JavaScript
'use client';
import _extends from "@babel/runtime/helpers/esm/extends";
import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
var _excluded = ["as", "data", "style", "showIndentLine", "value", "locale", "height", "className", "searchable", "classPrefix", "searchKeyword", "searchBy", "draggable", "disabledItemValues", "loadingNodeValues", "flattenedNodes", "listProps", "listRef", "searchInputRef", "expandItemValues", "onSearch", "onSelect", "onSelectItem", "onChange", "onDragEnd", "onDragStart", "onDragEnter", "onDragLeave", "onDragOver", "onDrop", "onExpand", "onFocusItem", "onScroll"];
import React, { useEffect, useMemo } from 'react';
import isNil from 'lodash/isNil';
import TreeViewNode from "./TreeNode.js";
import IndentLine from "./IndentLine.js";
import useTreeSearch from "./hooks/useTreeSearch.js";
import useTreeDrag from "./hooks/useTreeDrag.js";
import useFocusTree from "./hooks/useFocusTree.js";
import useVirtualizedTreeData from "./hooks/useVirtualizedTreeData.js";
import useTreeNodeProps from "./hooks/useTreeNodeProps.js";
import SearchBox from "../internals/SearchBox/index.js";
import { List, AutoSizer, defaultItemSize } from "../internals/Windowing/index.js";
import { getPathTowardsItem, getKeyParentMap } from "../internals/Tree/utils/index.js";
import { useClassNames, useEventCallback } from "../internals/hooks/index.js";
import { isExpand, hasVisibleChildren, getActiveItem } from "./utils/index.js";
import { onMenuKeyDown } from "../internals/Picker/index.js";
import { TreeView as BaseTreeView } from "../internals/Tree/index.js";
import { useTreeContextProps } from "../internals/Tree/TreeProvider.js";
import { useCustom } from "../CustomProvider/index.js";
/**
* Props for the TreeViewInner component.
*/
/**
* Represents the props for the TreeView component.
*/
var TreeView = /*#__PURE__*/React.forwardRef(function (props, ref) {
var _props$as = props.as,
Component = _props$as === void 0 ? 'div' : _props$as,
_props$data = props.data,
data = _props$data === void 0 ? [] : _props$data,
style = props.style,
showIndentLine = props.showIndentLine,
valueProp = props.value,
overrideLocale = props.locale,
_props$height = props.height,
height = _props$height === void 0 ? 360 : _props$height,
className = props.className,
_props$searchable = props.searchable,
searchable = _props$searchable === void 0 ? false : _props$searchable,
_props$classPrefix = props.classPrefix,
classPrefix = _props$classPrefix === void 0 ? 'tree' : _props$classPrefix,
searchKeyword = props.searchKeyword,
searchBy = props.searchBy,
draggable = props.draggable,
_props$disabledItemVa = props.disabledItemValues,
disabledItemValues = _props$disabledItemVa === void 0 ? [] : _props$disabledItemVa,
_props$loadingNodeVal = props.loadingNodeValues,
loadingNodeValues = _props$loadingNodeVal === void 0 ? [] : _props$loadingNodeVal,
_props$flattenedNodes = props.flattenedNodes,
flattenedNodes = _props$flattenedNodes === void 0 ? {} : _props$flattenedNodes,
listProps = props.listProps,
listRef = props.listRef,
searchInputRef = props.searchInputRef,
_props$expandItemValu = props.expandItemValues,
expandItemValues = _props$expandItemValu === void 0 ? [] : _props$expandItemValu,
onSearch = props.onSearch,
onSelect = props.onSelect,
onSelectItem = props.onSelectItem,
onChange = props.onChange,
onDragEnd = props.onDragEnd,
onDragStart = props.onDragStart,
onDragEnter = props.onDragEnter,
onDragLeave = props.onDragLeave,
onDragOver = props.onDragOver,
onDrop = props.onDrop,
onExpand = props.onExpand,
onFocusItem = props.onFocusItem,
onScroll = props.onScroll,
rest = _objectWithoutPropertiesLoose(props, _excluded);
var _useCustom = useCustom(),
getLocale = _useCustom.getLocale;
var _getLocale = getLocale('Combobox', overrideLocale),
searchPlaceholder = _getLocale.searchPlaceholder,
noResultsText = _getLocale.noResultsText;
var _useTreeContextProps = useTreeContextProps(),
valueKey = _useTreeContextProps.valueKey,
childrenKey = _useTreeContextProps.childrenKey,
scrollShadow = _useTreeContextProps.scrollShadow,
virtualized = _useTreeContextProps.virtualized;
var _useClassNames = useClassNames(classPrefix),
prefix = _useClassNames.prefix,
merge = _useClassNames.merge,
withClassPrefix = _useClassNames.withClassPrefix;
var handleSearchCallback = useEventCallback(function (value, _data, event) {
onSearch === null || onSearch === void 0 || onSearch(value, event);
});
var _useTreeSearch = useTreeSearch({
callback: handleSearchCallback,
searchKeyword: searchKeyword,
data: data,
searchBy: searchBy
}),
filteredData = _useTreeSearch.filteredData,
keyword = _useTreeSearch.keyword,
setFilteredData = _useTreeSearch.setFilteredData,
handleSearch = _useTreeSearch.handleSearch;
var transformation = useVirtualizedTreeData(flattenedNodes, filteredData, {
expandItemValues: expandItemValues,
searchKeyword: keyword
});
var getFormattedNodes = function getFormattedNodes(render) {
if (virtualized) {
return transformation().filter(function (n) {
return n.visible;
});
}
return filteredData.map(function (dataItem, index) {
return render === null || render === void 0 ? void 0 : render(dataItem, index, 1);
}).filter(function (n) {
return n;
});
};
useEffect(function () {
setFilteredData(data, keyword);
}, [data, keyword, setFilteredData]);
// TODO-Doma
// Replace `getKeyParentMap` with `getParentMap`
var itemParentMap = useMemo(function () {
return getKeyParentMap(data, function (node) {
return node[valueKey];
}, function (node) {
return node[childrenKey];
});
}, [childrenKey, data, valueKey]);
var _useFocusTree = useFocusTree({
filteredData: filteredData,
disabledItemValues: disabledItemValues,
expandItemValues: expandItemValues,
searchKeyword: keyword,
flattenedNodes: flattenedNodes,
onFocused: onFocusItem,
onExpand: onExpand
}),
focusItemValue = _useFocusTree.focusItemValue,
setFocusItemValue = _useFocusTree.setFocusItemValue,
onTreeKeydown = _useFocusTree.onTreeKeydown,
treeNodesRefs = _useFocusTree.treeNodesRefs,
saveTreeNodeRef = _useFocusTree.saveTreeNodeRef,
treeViewRef = _useFocusTree.treeViewRef;
var _useTreeDrag = useTreeDrag({
flattenedNodes: flattenedNodes,
treeNodesRefs: treeNodesRefs,
draggable: draggable,
onDragStart: onDragStart,
onDragEnter: onDragEnter,
onDragOver: onDragOver,
onDragLeave: onDragLeave,
onDragEnd: onDragEnd,
onDrop: onDrop,
prefix: prefix
}),
dragNode = _useTreeDrag.dragNode,
dragOverNodeKey = _useTreeDrag.dragOverNodeKey,
dropNodePosition = _useTreeDrag.dropNodePosition,
dragEvents = _useTreeDrag.dragEvents;
var getTreeNodeProps = useTreeNodeProps({
value: valueProp,
disabledItemValues: disabledItemValues,
loadingNodeValues: loadingNodeValues,
focusItemValue: focusItemValue,
keyword: keyword,
dragNode: dragNode,
dragOverNodeKey: dragOverNodeKey,
dropNodePosition: dropNodePosition
});
var handleSelect = useEventCallback(function (nodeData, event) {
if (!nodeData) {
return;
}
var nextValue = nodeData[valueKey];
var path = getPathTowardsItem(nodeData, function (item) {
return itemParentMap.get(item[valueKey]);
});
setFocusItemValue(nextValue);
onChange === null || onChange === void 0 || onChange(nextValue, event);
onSelect === null || onSelect === void 0 || onSelect(nodeData, nextValue, event);
onSelectItem === null || onSelectItem === void 0 || onSelectItem(nodeData, path);
});
var selectActiveItem = useEventCallback(function (event) {
if (isNil(focusItemValue)) return;
var activeItem = getActiveItem(focusItemValue, flattenedNodes, valueKey);
handleSelect(activeItem, event);
});
var handleTreeKeyDown = useEventCallback(function (event) {
onTreeKeydown(event);
onMenuKeyDown(event, {
enter: selectActiveItem
});
});
var _renderNode = function renderNode(node, index, layer) {
var visible = node.visible;
if (!visible) {
return null;
}
var children = node[childrenKey];
var expanded = isExpand(keyword, expandItemValues.includes(node[valueKey]));
var hasChildren = keyword ? hasVisibleChildren(node, childrenKey) : Boolean(children);
var nodeProps = _extends({}, getTreeNodeProps(node, layer, index), dragEvents, {
expanded: expanded,
draggable: draggable,
onExpand: onExpand,
onSelect: handleSelect,
hasChildren: hasChildren
});
if (hasChildren) {
var _merge;
layer += 1;
var childClassName = merge(prefix('node-children'), (_merge = {}, _merge[prefix('node-expanded')] = expanded, _merge));
return /*#__PURE__*/React.createElement("div", {
className: childClassName,
key: node[valueKey]
}, /*#__PURE__*/React.createElement(TreeViewNode, _extends({}, nodeProps, {
ref: function ref(_ref) {
return saveTreeNodeRef(_ref, node.refKey);
}
})), /*#__PURE__*/React.createElement("div", {
className: prefix('group'),
role: "group"
}, children === null || children === void 0 ? void 0 : children.map(function (child, i) {
return _renderNode(child, i, layer);
}), showIndentLine && /*#__PURE__*/React.createElement(IndentLine, null)));
}
return /*#__PURE__*/React.createElement(TreeViewNode, _extends({
ref: function ref(_ref2) {
return saveTreeNodeRef(_ref2, node.refKey);
},
key: node[valueKey]
}, nodeProps));
};
var renderVirtualListNode = function renderVirtualListNode(_ref3) {
var index = _ref3.index,
style = _ref3.style,
data = _ref3.data;
var node = data[index];
var layer = node.layer,
visible = node.visible,
hasChildren = node.hasChildren;
var expanded = isExpand(keyword, expandItemValues.includes(node[valueKey]));
if (!visible) {
return null;
}
var treeNodeProps = _extends({}, getTreeNodeProps(node, layer), dragEvents, {
expanded: expanded,
style: style,
onExpand: onExpand,
onSelect: handleSelect,
hasChildren: hasChildren
});
return visible && /*#__PURE__*/React.createElement(TreeViewNode, _extends({
ref: function ref(_ref4) {
return saveTreeNodeRef(_ref4, node.refKey);
}
}, treeNodeProps));
};
var classes = merge(withClassPrefix({
virtualized: virtualized
}), className);
var formattedNodes = getFormattedNodes(_renderNode);
return /*#__PURE__*/React.createElement(Component, {
ref: ref,
className: classes,
style: style
}, searchable ? /*#__PURE__*/React.createElement(SearchBox, {
placeholder: searchPlaceholder,
onChange: handleSearch,
value: keyword,
inputRef: searchInputRef
}) : null, keyword && formattedNodes.length === 0 ? /*#__PURE__*/React.createElement("div", {
className: prefix('empty')
}, noResultsText) : null, /*#__PURE__*/React.createElement(BaseTreeView, _extends({}, rest, {
ref: treeViewRef,
treeRootClassName: prefix('root'),
onScroll: onScroll,
onKeyDown: handleTreeKeyDown,
className: prefix('view'),
height: height
}), virtualized ? /*#__PURE__*/React.createElement(AutoSizer, {
defaultHeight: height,
style: {
width: 'auto',
height: 'auto'
},
className: prefix('virt-auto-sizer')
}, function (_ref5) {
var height = _ref5.height;
return /*#__PURE__*/React.createElement(List, _extends({
ref: listRef,
height: height,
itemSize: defaultItemSize,
itemCount: formattedNodes.length,
itemData: formattedNodes,
className: prefix('virt-list'),
scrollShadow: scrollShadow
}, listProps), renderVirtualListNode);
}) : formattedNodes));
});
TreeView.displayName = 'TreeView';
export default TreeView;