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