diff --git a/src/OptionList.tsx b/src/OptionList.tsx index d2157e00..3d02df74 100644 --- a/src/OptionList.tsx +++ b/src/OptionList.tsx @@ -182,41 +182,24 @@ const OptionList: React.ForwardRefRenderFunction = (_, }; // ========================== Get Next Matching Node ========================== + const availableNodesRef = React.useRef[]>([]); + const getNextMatchingNode = ( - nodes: EventDataNode[], currentKey: Key | null, direction: 'next' | 'prev' = 'next', ): EventDataNode | null => { - const availableNodes: EventDataNode[] = []; - - const collectNodes = (nodeList: EventDataNode[]) => { - nodeList.forEach(node => { - if (!node.disabled && node.selectable !== false) { - // only collect selected nodes - if (displayValues?.some(v => v.value === node[fieldNames.value])) { - availableNodes.push(node); - } - } - if (node[fieldNames.children]) { - collectNodes(node[fieldNames.children]); - } - }); - }; - - collectNodes(nodes); + const availableNodes = availableNodesRef.current; if (availableNodes.length === 0) { return null; } - // if no current selected node, return first available node if (!currentKey) { return availableNodes[0]; } const currentIndex = availableNodes.findIndex(node => node[fieldNames.value] === currentKey); - // if current node is not in available nodes list, return first node if (currentIndex === -1) { return availableNodes[0]; } @@ -229,6 +212,27 @@ const OptionList: React.ForwardRefRenderFunction = (_, return availableNodes[nextIndex]; }; + React.useEffect(() => { + const nodes: EventDataNode[] = []; + const selectedValueSet = new Set(displayValues?.map(v => v.value)); + + const collectNodes = (nodeList: EventDataNode[]) => { + nodeList.forEach(node => { + if (!node.disabled && node.selectable !== false) { + if (selectedValueSet.has(node[fieldNames.value])) { + nodes.push(node); + } + } + if (node[fieldNames.children]) { + collectNodes(node[fieldNames.children]); + } + }); + }; + + collectNodes(memoTreeData); + availableNodesRef.current = nodes; + }, [displayValues, memoTreeData]); + // ========================== Active ========================== const [activeKey, setActiveKey] = React.useState(null); const activeEntity = keyEntities[activeKey as SafeKey]; @@ -268,10 +272,9 @@ const OptionList: React.ForwardRefRenderFunction = (_, if (isOverMaxCount) { event.preventDefault(); const direction = which === KeyCode.UP || which === KeyCode.LEFT ? 'prev' : 'next'; - const nextNode = getNextMatchingNode(memoTreeData, activeKey, direction); + const nextNode = getNextMatchingNode(activeKey, direction); if (nextNode) { setActiveKey(nextNode[fieldNames.value]); - // ensure scroll to visible area treeRef.current?.scrollTo({ key: nextNode[fieldNames.value] }); } } else { @@ -315,7 +318,7 @@ const OptionList: React.ForwardRefRenderFunction = (_, return; } - const nextNode = getNextMatchingNode(memoTreeData, key); + const nextNode = getNextMatchingNode(key); if (nextNode) { setActiveKey(nextNode[fieldNames.value]); }