UNPKG

rsuite

Version:

A suite of react components

280 lines (265 loc) 8.72 kB
'use client'; import _isUndefined from "lodash/isUndefined"; import _isNil from "lodash/isNil"; import { CHECK_STATE } from "../internals/constants/index.js"; import { attachParent, shallowEqual } from "../internals/utils/index.js"; import { formatNodeRefKey } from "../Tree/utils/index.js"; /** * Retrieves the children of a given parent node from a flattened node map. * Filters out uncheckable children. * Note: Does NOT filter disabled children - disabled children are still considered in check state calculations */ function getChildrenByFlattenNodes(nodes, parent) { if (!_isNil(parent.refKey) && _isNil(nodes[parent.refKey])) { return []; } return Object.values(nodes).filter(item => { var _item$parent; return (item === null || item === void 0 || (_item$parent = item.parent) === null || _item$parent === void 0 ? void 0 : _item$parent.refKey) === parent.refKey && item.refKey && !nodes[item.refKey].uncheckable; }); } /** * Checks if every child of a given parent node is checked. * Disabled children are ignored in this check. */ export function isEveryChildChecked(parent, options) { const { nodes, childrenKey, disabledItemValues = [], valueKey = 'value' } = options; if (_isNil(parent.refKey) || _isNil(nodes[parent.refKey])) { return false; } const children = getChildrenByFlattenNodes(nodes, parent); if (!children.length) { var _nodes$parent$refKey$; return (_nodes$parent$refKey$ = nodes[parent.refKey].check) !== null && _nodes$parent$refKey$ !== void 0 ? _nodes$parent$refKey$ : false; } // Filter out disabled children const enabledChildren = children.filter(child => { const isDisabled = getDisabledState(nodes, child, { disabledItemValues, valueKey }); return !isDisabled; }); // If all children are disabled, return the parent's own check state if (enabledChildren.length === 0) { var _nodes$parent$refKey$2; return (_nodes$parent$refKey$2 = nodes[parent.refKey].check) !== null && _nodes$parent$refKey$2 !== void 0 ? _nodes$parent$refKey$2 : false; } // Check if all enabled children are checked return enabledChildren.every(child => { var _child$childrenKey; if ((child === null || child === void 0 || (_child$childrenKey = child[childrenKey]) === null || _child$childrenKey === void 0 ? void 0 : _child$childrenKey.length) > 0) { // fix: #3559 return isEveryChildChecked(child, { nodes, childrenKey, disabledItemValues, valueKey }); } return !_isNil(child.refKey) && nodes[child.refKey].check; }); } /** * Checks if any child node is checked. * Disabled children are ignored in this check. */ export function isSomeChildChecked(nodes, parent, childrenKey, disabledItemValues = [], valueKey = 'value') { if (!_isNil(parent.refKey) && _isNil(nodes[parent.refKey])) { return false; } const children = getChildrenByFlattenNodes(nodes, parent); return children.some(child => { var _child$childrenKey2; // Skip disabled children const isDisabled = getDisabledState(nodes, child, { disabledItemValues, valueKey }); if (isDisabled) { return false; // Disabled children don't count as "some checked" } if ((child === null || child === void 0 || (_child$childrenKey2 = child[childrenKey]) === null || _child$childrenKey2 === void 0 ? void 0 : _child$childrenKey2.length) > 0) { return isSomeChildChecked(nodes, child, childrenKey, disabledItemValues, valueKey); } return !_isNil(child.refKey) && nodes[child.refKey].check; }); } /** * Checks if any node in the data has a grandchild. */ export function hasGrandchild(data, childrenKey) { return data.some(node => Array.isArray(node[childrenKey])); } /** * Checks if all sibling nodes of a given node are uncheckable. */ export function isAllSiblingNodeUncheckable(node, nodes, uncheckableItemValues, valueKey) { const list = []; const parentNodeRefKey = node.parent ? node.parent.refKey : ''; Object.keys(nodes).forEach(refKey => { var _curNode$parent; const curNode = nodes[refKey]; if (_isNil(node.parent) && _isNil(curNode.parent)) { list.push(curNode); } else if (((_curNode$parent = curNode.parent) === null || _curNode$parent === void 0 ? void 0 : _curNode$parent.refKey) === parentNodeRefKey) { list.push(curNode); } }); return list.every(node => isNodeUncheckable(node, { uncheckableItemValues, valueKey })); } /** * Checks if every first-level node is uncheckable based on the provided criteria. */ export function isEveryFirstLevelNodeUncheckable(nodes, uncheckableItemValues, valueKey) { const list = []; Object.keys(nodes).forEach(refKey => { const curNode = nodes[refKey]; if (!curNode.parent) { list.push(curNode); } }); return list.every(node => isNodeUncheckable(node, { uncheckableItemValues, valueKey })); } /** * Checks if a node is uncheckable. */ export function isNodeUncheckable(node, props) { const { uncheckableItemValues = [], valueKey } = props; return uncheckableItemValues.some(value => node[valueKey] === value); } export function getFormattedTree(nodes, data, props) { const { childrenKey, cascade, disabledItemValues, valueKey } = props; return data.map(node => { const formatted = { ...node }; const curNode = nodes[node.refKey]; if (curNode) { var _node$childrenKey; const checkState = !_isUndefined(cascade) ? getNodeCheckState(curNode, { cascade, nodes, childrenKey, disabledItemValues, valueKey }) : undefined; formatted.check = curNode.check; formatted.uncheckable = curNode.uncheckable; attachParent(formatted, curNode.parent); formatted.checkState = checkState; if (((_node$childrenKey = node[childrenKey]) === null || _node$childrenKey === void 0 ? void 0 : _node$childrenKey.length) > 0) { formatted[childrenKey] = getFormattedTree(nodes, formatted[childrenKey], props); } } return formatted; }); } /** * Determines the disabled state of a tree node. * If a parent node is disabled, all its children should also be disabled. */ export function getDisabledState(nodes, node, props) { const { disabledItemValues = [], valueKey } = props; if (!_isNil(node.refKey) && _isNil(nodes[node.refKey])) { return false; } // Check if the current node is disabled const isCurrentNodeDisabled = disabledItemValues.some(value => node.refKey && shallowEqual(nodes[node.refKey][valueKey], value)); if (isCurrentNodeDisabled) { return true; } // Check if any parent node is disabled let currentNode = node; while (currentNode.parent) { const parentNode = currentNode.parent; const parentRefKey = parentNode.refKey; if (!_isNil(parentRefKey) && !_isNil(nodes[parentRefKey]) && disabledItemValues.some(value => shallowEqual(nodes[parentRefKey][valueKey], value))) { return true; } currentNode = parentNode; } return false; } /** * Returns the default value for the check tree. */ export function getCheckTreeDefaultValue(value, uncheckableItemValues) { if (Array.isArray(value) && Array.isArray(uncheckableItemValues)) { return value.filter(v => !uncheckableItemValues.includes(v)); } return value; } /** * Retrieves the selected items from the given nodes. */ export function getSelectedItems(nodes, values) { const checkedItems = []; values.forEach(value => { const refKey = formatNodeRefKey(value); const node = nodes[refKey]; if (!_isNil(node)) { checkedItems.push(node); } }); return checkedItems; } /** * Calculates the check state of a node in a check tree. */ export function getNodeCheckState(node, options) { const { nodes, cascade, childrenKey, disabledItemValues = [], valueKey = 'value' } = options; if (node.refKey === undefined) { return CHECK_STATE.UNCHECK; } if (_isNil(nodes[node.refKey])) { return CHECK_STATE.UNCHECK; } if (!node[childrenKey] || !node[childrenKey].length || !cascade) { nodes[node.refKey].checkAll = false; return node.check ? CHECK_STATE.CHECK : CHECK_STATE.UNCHECK; } if (isEveryChildChecked(node, { nodes, childrenKey, disabledItemValues, valueKey })) { nodes[node.refKey].checkAll = true; nodes[node.refKey].check = true; return CHECK_STATE.CHECK; } if (isSomeChildChecked(nodes, node, childrenKey, disabledItemValues, valueKey)) { nodes[node.refKey].checkAll = false; return CHECK_STATE.INDETERMINATE; } return CHECK_STATE.UNCHECK; }