| 475 | } |
| 476 | |
| 477 | function moveItems<T extends object>( |
| 478 | state: TreeDataState<T>, |
| 479 | keys: Iterable<Key>, |
| 480 | toParent: TreeNode<T> | null, |
| 481 | toIndex: number, |
| 482 | updateTree: ( |
| 483 | items: TreeNode<T>[], |
| 484 | key: Key | null, |
| 485 | update: (node: TreeNode<T>) => TreeNode<T> | null, |
| 486 | originalMap: Map<Key, TreeNode<T>> |
| 487 | ) => TreeDataState<T>, |
| 488 | addNode: (node: TreeNode<T>, map: Map<Key, TreeNode<T>>) => void |
| 489 | ): TreeDataState<T> { |
| 490 | let {items, nodeMap} = state; |
| 491 | |
| 492 | let parent = toParent; |
| 493 | let removeKeys = new Set(keys); |
| 494 | while (parent?.parentKey != null) { |
| 495 | if (removeKeys.has(parent.key)) { |
| 496 | throw new Error('Cannot move an item to be a child of itself.'); |
| 497 | } |
| 498 | parent = nodeMap.get(parent.parentKey!) ?? null; |
| 499 | } |
| 500 | |
| 501 | let originalToIndex = toIndex; |
| 502 | |
| 503 | let keyArray = Array.isArray(keys) ? keys : [...keys]; |
| 504 | // depth first search to put keys in order |
| 505 | let inOrderKeys: Map<Key, number> = new Map(); |
| 506 | let removedItems: Array<TreeNode<T>> = []; |
| 507 | let newItems = items; |
| 508 | let newMap = nodeMap; |
| 509 | let i = 0; |
| 510 | |
| 511 | function traversal(node, {inorder, postorder}) { |
| 512 | inorder?.(node); |
| 513 | if (node != null) { |
| 514 | for (let child of node.children ?? []) { |
| 515 | traversal(child, {inorder, postorder}); |
| 516 | postorder?.(child); |
| 517 | } |
| 518 | } |
| 519 | } |
| 520 | |
| 521 | function inorder(child) { |
| 522 | // in-order so we add items as we encounter them in the tree, then we can insert them in expected order later |
| 523 | if (keyArray.includes(child.key)) { |
| 524 | inOrderKeys.set(child.key, i++); |
| 525 | } |
| 526 | } |
| 527 | |
| 528 | function postorder(child) { |
| 529 | // remove items and update the tree from the leaves and work upwards toward the root, this way |
| 530 | // we don't copy child node references from parents inadvertently |
| 531 | if (keyArray.includes(child.key)) { |
| 532 | removedItems.push({...newMap.get(child.key)!, parentKey: toParent?.key ?? null}); |
| 533 | let {items: nextItems, nodeMap: nextMap} = updateTree( |
| 534 | newItems, |