| 150 | * update the data over time. |
| 151 | */ |
| 152 | export function useTreeData<T extends object>(options: TreeOptions<T>): TreeData<T> { |
| 153 | let { |
| 154 | initialItems = [], |
| 155 | initialSelectedKeys, |
| 156 | getKey = (item: any) => item.id ?? item.key, |
| 157 | getChildren = (item: any) => item.children |
| 158 | } = options; |
| 159 | |
| 160 | // We only want to compute this on initial render. |
| 161 | let [tree, setItems] = useState<TreeDataState<T>>(() => buildTree(initialItems, new Map())); |
| 162 | let {items, nodeMap} = tree; |
| 163 | |
| 164 | let [selectedKeys, setSelectedKeys] = useState(new Set<Key>(initialSelectedKeys || [])); |
| 165 | |
| 166 | function buildTree( |
| 167 | initialItems: T[] | null = [], |
| 168 | map: Map<Key, TreeNode<T>>, |
| 169 | parentKey?: Key | null |
| 170 | ) { |
| 171 | if (initialItems == null) { |
| 172 | initialItems = []; |
| 173 | } |
| 174 | return { |
| 175 | items: initialItems.map(item => { |
| 176 | let node: TreeNode<T> = { |
| 177 | key: getKey(item), |
| 178 | parentKey: parentKey ?? null, |
| 179 | value: item, |
| 180 | children: null |
| 181 | }; |
| 182 | |
| 183 | node.children = buildTree(getChildren(item), map, node.key).items; |
| 184 | map.set(node.key, node); |
| 185 | return node; |
| 186 | }), |
| 187 | nodeMap: map |
| 188 | }; |
| 189 | } |
| 190 | |
| 191 | function updateTree( |
| 192 | items: TreeNode<T>[], |
| 193 | key: Key | null, |
| 194 | update: (node: TreeNode<T>) => TreeNode<T> | null, |
| 195 | originalMap: Map<Key, TreeNode<T>> |
| 196 | ) { |
| 197 | let node = key == null ? null : originalMap.get(key); |
| 198 | if (node == null) { |
| 199 | return {items, nodeMap: originalMap}; |
| 200 | } |
| 201 | let map = new Map<Key, TreeNode<T>>(originalMap); |
| 202 | |
| 203 | // Create a new node. If null, then delete the node, otherwise replace. |
| 204 | let newNode = update(node); |
| 205 | if (newNode == null) { |
| 206 | deleteNode(node, map); |
| 207 | } else { |
| 208 | addNode(newNode, map); |
| 209 | } |