📄 useTreeData.cjs
/home/palash/git/site/node_modules/react-stately/dist/private/data/useTreeData.cjs
Language: cjs • Lines: 329
var $8NoZA$react = require("react");


function $parcel$export(e, n, v, s) {
  Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});
}

$parcel$export(module.exports, "useTreeData", function () { return $ab40f19b6fb67f7e$export$d14e1352e21f4a16; });
/*
 * 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 $ab40f19b6fb67f7e$export$d14e1352e21f4a16(options) {
    let { initialItems: initialItems = [], initialSelectedKeys: initialSelectedKeys, getKey: getKey = (item)=>item.id ?? item.key, getChildren: getChildren = (item)=>item.children } = options;
    // We only want to compute this on initial render.
    let [tree, setItems] = (0, $8NoZA$react.useState)(()=>buildTree(initialItems, new Map()));
    let { items: items, nodeMap: nodeMap } = tree;
    let [selectedKeys, setSelectedKeys] = (0, $8NoZA$react.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,
                    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);
            copy.children = children?.map((child)=>{
                if (child === node) // newNode cannot be null here due to the above filter.
                return newNode;
                return child;
            }) ?? 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);
            this.insert(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);
            this.insert(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;
                let toParentKey = node.parentKey ?? null;
                let parent = null;
                if (toParentKey != null) parent = nodeMap.get(toParentKey) ?? null;
                let toIndex = parent?.children ? parent.children.indexOf(node) : items.indexOf(node);
                return $ab40f19b6fb67f7e$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;
                let toParentKey = node.parentKey ?? null;
                let parent = null;
                if (toParentKey != null) parent = nodeMap.get(toParentKey) ?? null;
                let toIndex = parent?.children ? parent.children.indexOf(node) : items.indexOf(node);
                toIndex++;
                return $ab40f19b6fb67f7e$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 $ab40f19b6fb67f7e$var$moveItems(state, keys, toParent, toIndex, updateTree, addNode) {
    let { items: items, nodeMap: nodeMap } = state;
    let parent = toParent;
    let removeKeys = new Set(keys);
    while(parent?.parentKey != null){
        if (removeKeys.has(parent.key)) throw new Error('Cannot move an item to be a child of itself.');
        parent = nodeMap.get(parent.parentKey) ?? 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?.(node);
        if (node != null) for (let child of node.children ?? []){
            traversal(child, {
                inorder: inorder,
                postorder: postorder
            });
            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)) {
            removedItems.push({
                ...newMap.get(child.key),
                parentKey: 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?.key) && keyArray.includes(child.key) && (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);
}


//# sourceMappingURL=useTreeData.cjs.map