📄 useTreeData.js
/home/palash/git/site/node_modules/react-stately/dist/private/data/useTreeData.js
Language: js • Lines: 337
import {useState as $l7jaK$useState} from "react";

/*
 * Copyright 2020 Adobe. All rights reserved.
 * This file is licensed to you under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License. You may obtain a copy
 * of the License at http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under
 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
 * OF ANY KIND, either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */ 
function $fed32bb7b9c8a2e7$export$d14e1352e21f4a16(options) {
    let { initialItems: initialItems = [], initialSelectedKeys: initialSelectedKeys, getKey: getKey = (item)=>{
        var _item_id;
        return (_item_id = item.id) !== null && _item_id !== void 0 ? _item_id : item.key;
    }, getChildren: getChildren = (item)=>item.children } = options;
    // We only want to compute this on initial render.
    let [tree, setItems] = (0, $l7jaK$useState)(()=>buildTree(initialItems, new Map()));
    let { items: items, nodeMap: nodeMap } = tree;
    let [selectedKeys, setSelectedKeys] = (0, $l7jaK$useState)(new Set(initialSelectedKeys || []));
    function buildTree(initialItems = [], map, parentKey) {
        if (initialItems == null) initialItems = [];
        return {
            items: initialItems.map((item)=>{
                let node = {
                    key: getKey(item),
                    parentKey: parentKey !== null && parentKey !== void 0 ? parentKey : null,
                    value: item,
                    children: null
                };
                node.children = buildTree(getChildren(item), map, node.key).items;
                map.set(node.key, node);
                return node;
            }),
            nodeMap: map
        };
    }
    function updateTree(items, key, update, originalMap) {
        let node = key == null ? null : originalMap.get(key);
        if (node == null) return {
            items: items,
            nodeMap: originalMap
        };
        let map = new Map(originalMap);
        // Create a new node. If null, then delete the node, otherwise replace.
        let newNode = update(node);
        if (newNode == null) deleteNode(node, map);
        else addNode(newNode, map);
        // Walk up the tree and update each parent to refer to the new children.
        while(node && node.parentKey){
            let nextParent = map.get(node.parentKey);
            let copy = {
                key: nextParent.key,
                parentKey: nextParent.parentKey,
                value: nextParent.value,
                children: null
            };
            let children = nextParent.children;
            if (newNode == null && children) children = children.filter((c)=>c !== node);
            var _children_map;
            copy.children = (_children_map = children === null || children === void 0 ? void 0 : children.map((child)=>{
                if (child === node) // newNode cannot be null here due to the above filter.
                return newNode;
                return child;
            })) !== null && _children_map !== void 0 ? _children_map : null;
            map.set(copy.key, copy);
            newNode = copy;
            node = nextParent;
        }
        if (newNode == null) items = items.filter((c)=>c !== node);
        return {
            items: items.map((item)=>{
                if (item === node) // newNode cannot be null here due to the above filter.
                return newNode;
                return item;
            }),
            nodeMap: map
        };
    }
    function addNode(node, map) {
        map.set(node.key, node);
        if (node.children) for (let child of node.children)addNode(child, map);
    }
    function deleteNode(node, map) {
        map.delete(node.key);
        if (node.children) for (let child of node.children)deleteNode(child, map);
    }
    return {
        items: items,
        selectedKeys: selectedKeys,
        setSelectedKeys: setSelectedKeys,
        getItem (key) {
            return nodeMap.get(key);
        },
        insert (parentKey, index, ...values) {
            setItems(({ items: items, nodeMap: originalMap })=>{
                let { items: newNodes, nodeMap: newMap } = buildTree(values, new Map(originalMap), parentKey);
                // If parentKey is null, insert into the root.
                if (parentKey == null) return {
                    items: [
                        ...items.slice(0, index),
                        ...newNodes,
                        ...items.slice(index)
                    ],
                    nodeMap: newMap
                };
                // Otherwise, update the parent node and its ancestors.
                return updateTree(items, parentKey, (parentNode)=>({
                        key: parentNode.key,
                        parentKey: parentNode.parentKey,
                        value: parentNode.value,
                        children: [
                            ...parentNode.children.slice(0, index),
                            ...newNodes,
                            ...parentNode.children.slice(index)
                        ]
                    }), newMap);
            });
        },
        insertBefore (key, ...values) {
            let node = nodeMap.get(key);
            if (!node) return;
            let parentNode = nodeMap.get(node.parentKey);
            let nodes = parentNode ? parentNode.children : items;
            let index = nodes.indexOf(node);
            var _parentNode_key;
            this.insert((_parentNode_key = parentNode === null || parentNode === void 0 ? void 0 : parentNode.key) !== null && _parentNode_key !== void 0 ? _parentNode_key : null, index, ...values);
        },
        insertAfter (key, ...values) {
            let node = nodeMap.get(key);
            if (!node) return;
            let parentNode = nodeMap.get(node.parentKey);
            let nodes = parentNode ? parentNode.children : items;
            let index = nodes.indexOf(node);
            var _parentNode_key;
            this.insert((_parentNode_key = parentNode === null || parentNode === void 0 ? void 0 : parentNode.key) !== null && _parentNode_key !== void 0 ? _parentNode_key : null, index + 1, ...values);
        },
        prepend (parentKey, ...values) {
            this.insert(parentKey, 0, ...values);
        },
        append (parentKey, ...values) {
            if (parentKey == null) this.insert(null, items.length, ...values);
            else {
                let parentNode = nodeMap.get(parentKey);
                if (!parentNode) return;
                this.insert(parentKey, parentNode.children.length, ...values);
            }
        },
        remove (...keys) {
            if (keys.length === 0) return;
            let newItems = items;
            let prevMap = nodeMap;
            let newTree;
            for (let key of keys){
                newTree = updateTree(newItems, key, ()=>null, prevMap);
                prevMap = newTree.nodeMap;
                newItems = newTree.items;
            }
            setItems(newTree);
            let selection = new Set(selectedKeys);
            for (let key of selectedKeys)if (!newTree.nodeMap.has(key)) selection.delete(key);
            setSelectedKeys(selection);
        },
        removeSelectedItems () {
            this.remove(...selectedKeys);
        },
        move (key, toParentKey, index) {
            setItems(({ items: items, nodeMap: originalMap })=>{
                let node = originalMap.get(key);
                if (!node) return {
                    items: items,
                    nodeMap: originalMap
                };
                let { items: newItems, nodeMap: newMap } = updateTree(items, key, ()=>null, originalMap);
                const movedNode = {
                    ...node,
                    parentKey: toParentKey
                };
                // If parentKey is null, insert into the root.
                if (toParentKey == null) {
                    addNode(movedNode, newMap);
                    return {
                        items: [
                            ...newItems.slice(0, index),
                            movedNode,
                            ...newItems.slice(index)
                        ],
                        nodeMap: newMap
                    };
                }
                // Otherwise, update the parent node and its ancestors.
                return updateTree(newItems, toParentKey, (parentNode)=>({
                        key: parentNode.key,
                        parentKey: parentNode.parentKey,
                        value: parentNode.value,
                        children: [
                            ...parentNode.children.slice(0, index),
                            movedNode,
                            ...parentNode.children.slice(index)
                        ]
                    }), newMap);
            });
        },
        moveBefore (key, keys) {
            setItems((prevState)=>{
                let { items: items, nodeMap: nodeMap } = prevState;
                let node = nodeMap.get(key);
                if (!node) return prevState;
                var _node_parentKey;
                let toParentKey = (_node_parentKey = node.parentKey) !== null && _node_parentKey !== void 0 ? _node_parentKey : null;
                let parent = null;
                var _nodeMap_get;
                if (toParentKey != null) parent = (_nodeMap_get = nodeMap.get(toParentKey)) !== null && _nodeMap_get !== void 0 ? _nodeMap_get : null;
                let toIndex = (parent === null || parent === void 0 ? void 0 : parent.children) ? parent.children.indexOf(node) : items.indexOf(node);
                return $fed32bb7b9c8a2e7$var$moveItems(prevState, keys, parent, toIndex, updateTree, addNode);
            });
        },
        moveAfter (key, keys) {
            setItems((prevState)=>{
                let { items: items, nodeMap: nodeMap } = prevState;
                let node = nodeMap.get(key);
                if (!node) return prevState;
                var _node_parentKey;
                let toParentKey = (_node_parentKey = node.parentKey) !== null && _node_parentKey !== void 0 ? _node_parentKey : null;
                let parent = null;
                var _nodeMap_get;
                if (toParentKey != null) parent = (_nodeMap_get = nodeMap.get(toParentKey)) !== null && _nodeMap_get !== void 0 ? _nodeMap_get : null;
                let toIndex = (parent === null || parent === void 0 ? void 0 : parent.children) ? parent.children.indexOf(node) : items.indexOf(node);
                toIndex++;
                return $fed32bb7b9c8a2e7$var$moveItems(prevState, keys, parent, toIndex, updateTree, addNode);
            });
        },
        update (oldKey, newValue) {
            setItems(({ items: items, nodeMap: originalMap })=>updateTree(items, oldKey, (oldNode)=>{
                    let node = {
                        key: oldNode.key,
                        parentKey: oldNode.parentKey,
                        value: newValue,
                        children: null
                    };
                    let tree = buildTree(getChildren(newValue), originalMap, node.key);
                    node.children = tree.items;
                    return node;
                }, originalMap));
        }
    };
}
function $fed32bb7b9c8a2e7$var$moveItems(state, keys, toParent, toIndex, updateTree, addNode) {
    let { items: items, nodeMap: nodeMap } = state;
    let parent = toParent;
    let removeKeys = new Set(keys);
    while((parent === null || parent === void 0 ? void 0 : parent.parentKey) != null){
        if (removeKeys.has(parent.key)) throw new Error('Cannot move an item to be a child of itself.');
        var _nodeMap_get;
        parent = (_nodeMap_get = nodeMap.get(parent.parentKey)) !== null && _nodeMap_get !== void 0 ? _nodeMap_get : null;
    }
    let originalToIndex = toIndex;
    let keyArray = Array.isArray(keys) ? keys : [
        ...keys
    ];
    // depth first search to put keys in order
    let inOrderKeys = new Map();
    let removedItems = [];
    let newItems = items;
    let newMap = nodeMap;
    let i = 0;
    function traversal(node, { inorder: inorder, postorder: postorder }) {
        inorder === null || inorder === void 0 ? void 0 : inorder(node);
        var _node_children;
        if (node != null) for (let child of (_node_children = node.children) !== null && _node_children !== void 0 ? _node_children : []){
            traversal(child, {
                inorder: inorder,
                postorder: postorder
            });
            postorder === null || postorder === void 0 ? void 0 : postorder(child);
        }
    }
    function inorder(child) {
        // in-order so we add items as we encounter them in the tree, then we can insert them in expected order later
        if (keyArray.includes(child.key)) inOrderKeys.set(child.key, i++);
    }
    function postorder(child) {
        // remove items and update the tree from the leaves and work upwards toward the root, this way
        // we don't copy child node references from parents inadvertently
        if (keyArray.includes(child.key)) {
            var _toParent_key;
            removedItems.push({
                ...newMap.get(child.key),
                parentKey: (_toParent_key = toParent === null || toParent === void 0 ? void 0 : toParent.key) !== null && _toParent_key !== void 0 ? _toParent_key : null
            });
            let { items: nextItems, nodeMap: nextMap } = updateTree(newItems, child.key, ()=>null, newMap);
            newItems = nextItems;
            newMap = nextMap;
        }
        // decrement the index if the child being removed is in the target parent and before the target index
        // the root node is special, it is null, and will not have a key, however, a parentKey can still point to it
        if ((child.parentKey === toParent || child.parentKey === (toParent === null || toParent === void 0 ? void 0 : toParent.key)) && keyArray.includes(child.key) && ((toParent === null || toParent === void 0 ? void 0 : toParent.children) ? toParent.children.indexOf(child) : items.indexOf(child)) < originalToIndex) toIndex--;
    }
    traversal({
        children: items
    }, {
        inorder: inorder,
        postorder: postorder
    });
    let inOrderItems = removedItems.sort((a, b)=>inOrderKeys.get(a.key) > inOrderKeys.get(b.key) ? 1 : -1);
    // If parentKey is null, insert into the root.
    if (!toParent || toParent.key == null) {
        inOrderItems.forEach((movedNode)=>{
            addNode(movedNode, newMap);
        });
        return {
            items: [
                ...newItems.slice(0, toIndex),
                ...inOrderItems,
                ...newItems.slice(toIndex)
            ],
            nodeMap: newMap
        };
    }
    // Otherwise, update the parent node and its ancestors.
    return updateTree(newItems, toParent.key, (parentNode)=>({
            key: parentNode.key,
            parentKey: parentNode.parentKey,
            value: parentNode.value,
            children: [
                ...parentNode.children.slice(0, toIndex),
                ...inOrderItems,
                ...parentNode.children.slice(toIndex)
            ]
        }), newMap);
}


export {$fed32bb7b9c8a2e7$export$d14e1352e21f4a16 as useTreeData};
//# sourceMappingURL=useTreeData.js.map