rsuite
Version:
A suite of react components
402 lines (335 loc) • 10.6 kB
JavaScript
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
};
}