UNPKG

rsuite

Version:

A suite of react components

402 lines (335 loc) 10.6 kB
import { useState, useEffect, useCallback } from 'react'; import uniq from 'lodash/uniq'; import remove from 'lodash/remove'; import slice from 'lodash/slice'; import { flattenTree } from '../utils/treeUtils'; /** * Get all parents of a node * @param node */ export var getParents = function getParents(node) { var parents = []; if (!node.parent) { return parents; } parents.push(node.parent); parents = parents.concat(getParents(node.parent)); return parents; }; /** * Check if any child nodes are selected. * @param node * @param value * @param itemKeys */ export var isSomeChildChecked = function isSomeChildChecked(node, value, itemKeys) { var childrenKey = itemKeys.childrenKey, valueKey = itemKeys.valueKey; if (!node[childrenKey] || !value) { return false; } return node[childrenKey].some(function (child) { var _child$childrenKey; if (value.some(function (n) { return n === child[valueKey]; })) { return true; } if ((_child$childrenKey = child[childrenKey]) !== null && _child$childrenKey !== void 0 && _child$childrenKey.length) { return isSomeChildChecked(child, value, itemKeys); } return false; }); }; /** * Check if the parent is selected. * @param node * @param value * @param itemKeys */ export var isSomeParentChecked = function isSomeParentChecked(node, value, itemKeys) { var valueKey = itemKeys.valueKey; if (!value) { return false; } if (value.some(function (n) { return n === node[valueKey]; })) { return true; } if (node.parent) { return isSomeParentChecked(node.parent, value, itemKeys); } return false; }; export var getOtherItemValuesByUnselectChild = function getOtherItemValuesByUnselectChild(itemNode, value, itemKeys) { var valueKey = itemKeys.valueKey, childrenKey = itemKeys.childrenKey; var parentValues = []; var itemValues = []; // Find the parent node of the current node by value function findParent(item) { parentValues.push(item[valueKey]); if (value.some(function (v) { return v === item[valueKey]; })) { return item; } if (item.parent) { var p = findParent(item.parent); if (p) { return p; } } return null; } // Get child nodes through parent node function pushChildValue(item) { if (!item[childrenKey]) { return; } item[childrenKey].forEach(function (n) { // Determine whether it is a direct parent if (parentValues.some(function (v) { return v === n[valueKey]; }) && n[childrenKey]) { pushChildValue(n); } else if (n[valueKey] !== itemNode[valueKey]) { itemValues.push(n[valueKey]); } }); } var parent = findParent(itemNode); if (!parent) { return []; } pushChildValue(parent); return itemValues; }; /** * Remove the values of all children. */ export var removeAllChildrenValue = function removeAllChildrenValue(value, item, itemKeys) { var valueKey = itemKeys.valueKey, childrenKey = itemKeys.childrenKey; var removedValue = []; if (!item[childrenKey]) { return; } item[childrenKey].forEach(function (n) { removedValue = removedValue.concat(remove(value, function (v) { return v === n[valueKey]; })); if (n[childrenKey]) { removeAllChildrenValue(value, n, itemKeys); } }); return removedValue; }; /** * A hook to flatten tree structure data * @param data */ export function useFlattenData(data, itemKeys) { var childrenKey = itemKeys.childrenKey; var _useState = useState(flattenTree(data)), flattenData = _useState[0], setFlattenData = _useState[1]; var addFlattenData = useCallback(function (children, parent) { var nodes = children.map(function (child) { child.parent = parent; return child; }); parent[childrenKey] = nodes; setFlattenData([].concat(flattenData, nodes)); }, [childrenKey, flattenData]); useEffect(function () { setFlattenData(flattenTree(data)); }, [data]); return { addFlattenData: addFlattenData, flattenData: flattenData }; } /** * A hook for column data * @param flattenData */ export function useColumnData(flattenData) { // The columns displayed in the cascading panel. var _useState2 = useState([flattenData.filter(function (item) { return !item.parent; })]), columnData = _useState2[0], setColumnData = _useState2[1]; /** * Add a list of options to the cascading panel. Used for lazy loading options. * @param column * @param index The index of the current column. */ function addColumn(column, index) { setColumnData([].concat(slice(columnData, 0, index), [column])); } function enforceUpdateColumnData(nextData) { var nextFlattenData = flattenTree(nextData); setColumnData([nextFlattenData.filter(function (item) { return !item.parent; })]); } return { columnData: columnData, addColumn: addColumn, setColumnData: setColumnData, enforceUpdateColumnData: enforceUpdateColumnData }; } /** * A hook that converts the value into a cascading value * @param props * @param flattenData */ export function useCascadeValue(props, flattenData) { var valueKey = props.valueKey, childrenKey = props.childrenKey, uncheckableItemValues = props.uncheckableItemValues, cascade = props.cascade, valueProp = props.value; /** * Get the values of all children */ var getChildrenValue = useCallback(function (item) { var values = []; if (!item[childrenKey]) { return values; } item[childrenKey].forEach(function (n) { if (uncheckableItemValues && !uncheckableItemValues.some(function (v) { return v === n[valueKey]; })) { values.push(n[valueKey]); } values = values.concat(getChildrenValue(n)); }); return values; }, [childrenKey, uncheckableItemValues, valueKey]); var splitValue = useCallback(function (item, checked, value) { var itemValue = item[valueKey]; var childrenValue = getChildrenValue(item); var parents = getParents(item); var nextValue = [].concat(value); var removedValue = []; if (checked) { nextValue.push(itemValue); // Delete all values under the current node removedValue = removedValue.concat(removeAllChildrenValue(nextValue, item, { valueKey: valueKey, childrenKey: childrenKey }) || []); // Traverse all ancestor nodes of the current node // Then determine whether all the child nodes of these nodes are selected, and then they themselves must be selected var _loop = function _loop(i) { // Whether the parent node can be selected var isCheckableParent = !(uncheckableItemValues !== null && uncheckableItemValues !== void 0 && uncheckableItemValues.some(function (v) { return v === parents[i][valueKey]; })); if (isCheckableParent) { var isCheckAll = parents[i][childrenKey] // Filter out options that are marked as not selectable .filter(function (n) { return !(uncheckableItemValues !== null && uncheckableItemValues !== void 0 && uncheckableItemValues.some(function (v) { return v === n[valueKey]; })); }) // Check if all nodes are selected .every(function (n) { return nextValue.some(function (v) { return v === n[valueKey]; }); }); if (isCheckAll) { // Add parent node value nextValue.push(parents[i][valueKey]); // Delete all values under the parent node removedValue = removedValue.concat(removeAllChildrenValue(nextValue, parents[i], { valueKey: valueKey, childrenKey: childrenKey }) || []); } } }; for (var i = 0; i < parents.length; i++) { _loop(i); } } else { var tempValue = childrenValue.concat(parents.map(function (item) { return item[valueKey]; })); nextValue = nextValue.concat(getOtherItemValuesByUnselectChild(item, nextValue, { valueKey: valueKey, childrenKey: childrenKey })); // Delete related child and parent nodes removedValue = remove(nextValue, function (v) { // Delete yourself if (v === itemValue) { return true; } return tempValue.some(function (n) { return n === v; }); }); } var uniqValue = uniq(nextValue); var uniqRemovedValue = uniq(removedValue); return { value: uniqValue, removedValue: uniqRemovedValue }; }, [valueKey, childrenKey, uncheckableItemValues, getChildrenValue]); var transformValue = useCallback(function (value) { if (value === void 0) { value = []; } if (!cascade) { return value; } var tempRemovedValue = []; var nextValue = []; var _loop2 = function _loop2(i) { // If the value in the current value is already in the deleted list, it will not be processed if (tempRemovedValue.some(function (v) { return v === value[i]; })) { return "continue"; } var item = flattenData.find(function (v) { return v[valueKey] === value[i]; }); if (!item) { return "continue"; } var sv = splitValue(item, true, value); tempRemovedValue = uniq(tempRemovedValue.concat(sv.removedValue)); // Get all relevant values nextValue = uniq(nextValue.concat(sv.value)); }; for (var i = 0; i < value.length; i++) { var _ret = _loop2(i); if (_ret === "continue") continue; } // Finally traverse all nextValue, and delete if its parent node is also nextValue return nextValue.filter(function (v) { var item = flattenData.find(function (n) { return n[valueKey] === v; }); if (item !== null && item !== void 0 && item.parent && nextValue.some(function (v) { return v === item.parent && item.parent[valueKey]; })) { return false; } return true; }); }, [cascade, flattenData, splitValue, valueKey]); var _useState3 = useState(transformValue(valueProp) || []), value = _useState3[0], setValue = _useState3[1]; useEffect(function () { // Update value when valueProp is updated. setValue(transformValue(valueProp) || []); }, [transformValue, valueProp]); return { value: value, setValue: setValue, splitValue: splitValue }; }