diff --git a/src/OptionList.tsx b/src/OptionList.tsx index be4d9dfe..2527625e 100644 --- a/src/OptionList.tsx +++ b/src/OptionList.tsx @@ -3,7 +3,7 @@ import type { RefOptionListProps } from '@rc-component/select/lib/OptionList'; import type { TreeProps } from '@rc-component/tree'; import Tree from '@rc-component/tree'; import { UnstableContext } from '@rc-component/tree'; -import type { EventDataNode, ScrollTo } from '@rc-component/tree/lib/interface'; +import type { DataEntity, EventDataNode, ScrollTo } from '@rc-component/tree/lib/interface'; import KeyCode from '@rc-component/util/lib/KeyCode'; import useMemo from '@rc-component/util/lib/hooks/useMemo'; import * as React from 'react'; @@ -178,15 +178,45 @@ const OptionList: React.ForwardRefRenderFunction = (_, const isLeaf = (entity.children || []).length === 0; if (!isLeaf) { - const checkableChildren = entity.children.filter( - childTreeNode => - !childTreeNode.node.disabled && - !childTreeNode.node.disableCheckbox && - !checkedKeys.includes(childTreeNode.node[fieldNames.value]), - ); - - const checkableChildrenCount = checkableChildren.length; - disabledCache.set(value, checkableChildrenCount > leftMaxCount); + const visited = new Set(); + const stack: DataEntity[] = [entity]; + let checkableCount = 0; + + while (stack.length > 0) { + const currentEntity = stack.pop(); + const currentValue = currentEntity.node[fieldNames.value]; + + if (visited.has(currentValue)) { + continue; + } + visited.add(currentValue); + + const isCurrentLeaf = (currentEntity.children || []).length === 0; + const isDisabled = + currentEntity.node.disabled || + currentEntity.node.disableCheckbox || + checkedKeys.includes(currentValue); + + if (isCurrentLeaf) { + if (!isDisabled) { + checkableCount++; + + // break early + if (checkableCount > leftMaxCount) { + disabledCache.set(value, true); + break; + } + } + continue; + } + + if (!isDisabled) { + for (let i = currentEntity.children.length - 1; i >= 0; i--) { + stack.push(currentEntity.children[i]); + } + } + } + disabledCache.set(value, checkableCount > leftMaxCount); } else { disabledCache.set(value, false); }