Skip to content

Commit 22b88d5

Browse files
committed
useTreeData - add getDescendantKeys method which is used to determine if a parent node can be dropped into its children
1 parent e6becc6 commit 22b88d5

File tree

3 files changed

+80
-0
lines changed

3 files changed

+80
-0
lines changed

packages/@react-spectrum/tree/stories/TreeView.stories.tsx

+6
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,12 @@ export const TreeExampleDynamicDragNDrop = (
262262
return;
263263
}
264264

265+
// you shouldn't be able to drop a parent into a child
266+
const dragNode = list.getItem(k);
267+
const childTreeKeys = list.getDescendantKeys(dragNode);
268+
if (childTreeKeys.includes(e.target.key)) {
269+
return null;
270+
}
265271
// node list index...
266272
let i = 0;
267273
if (parent) {

packages/@react-stately/data/src/useTreeData.ts

+20
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export interface TreeData<T extends object> {
5151
*/
5252
getItem(key: Key): TreeNode<T> | undefined,
5353

54+
getDescendantKeys(node?: TreeNode<T>): Key[],
5455
/**
5556
* Inserts an item into a parent node as a child.
5657
* @param parentKey - The key of the parent item to insert into. `null` for the root.
@@ -250,10 +251,29 @@ export function useTreeData<T extends object>(options: TreeOptions<T>): TreeData
250251
}
251252
}
252253

254+
function getDescendantKeys(node?: TreeNode<T>): Key[] {
255+
let descendantKeys: Key[] = [];
256+
if (!node) {
257+
return descendantKeys;
258+
}
259+
function recurse(currentNode: TreeNode<T>) {
260+
if (currentNode.children) {
261+
for (let child of currentNode.children) {
262+
descendantKeys.push(child.key);
263+
recurse(child);
264+
}
265+
}
266+
}
267+
268+
recurse(node);
269+
return descendantKeys;
270+
}
271+
253272
return {
254273
items,
255274
selectedKeys,
256275
setSelectedKeys,
276+
getDescendantKeys,
257277
getItem(key: Key) {
258278
return nodeMap.get(key);
259279
},

packages/@react-stately/data/test/useTreeData.test.js

+54
Original file line numberDiff line numberDiff line change
@@ -745,4 +745,58 @@ describe('useTreeData', function () {
745745
expect(result.current.items[1].key).toEqual('Emily');
746746
expect(result.current.items.length).toEqual(2);
747747
});
748+
749+
it('gets the decentants of a node', function () {
750+
const initialItems = [...initial, {name: 'Emily'}, {name: 'Eli'}];
751+
let {result} = renderHook(() =>
752+
useTreeData({initialItems, getChildren, getKey})
753+
);
754+
let decendants;
755+
act(() => {
756+
const top = result.current.getItem('David');
757+
decendants = result.current.getDescendantKeys(top);
758+
});
759+
expect(decendants).toEqual(['John', 'Suzie', 'Sam', 'Stacy', 'Brad', 'Jane']);
760+
});
761+
762+
763+
it('gets the decentants of a child node', function () {
764+
const initialItems = [...initial, {name: 'Emily'}, {name: 'Eli'}];
765+
let {result} = renderHook(() =>
766+
useTreeData({initialItems, getChildren, getKey})
767+
);
768+
let descendants;
769+
act(() => {
770+
const top = result.current.getItem('Sam');
771+
descendants = result.current.getDescendantKeys(top);
772+
});
773+
expect(descendants).toEqual(['Stacy', 'Brad']);
774+
});
775+
776+
it('returns an empty array when getting the decendant keys for a leaf node', function () {
777+
const initialItems = [...initial, {name: 'Emily'}, {name: 'Eli'}];
778+
let {result} = renderHook(() =>
779+
useTreeData({initialItems, getChildren, getKey})
780+
);
781+
let descendants;
782+
act(() => {
783+
const top = result.current.getItem('Eli');
784+
descendants = result.current.getDescendantKeys(top);
785+
});
786+
expect(descendants).toEqual([]);
787+
});
788+
789+
it('returns an empty array when an undefined key is supplied', function () {
790+
const initialItems = [...initial, {name: 'Emily'}, {name: 'Eli'}];
791+
let {result} = renderHook(() =>
792+
useTreeData({initialItems, getChildren, getKey})
793+
);
794+
let descendants;
795+
act(() => {
796+
descendants = result.current.getDescendantKeys(undefined);
797+
});
798+
expect(descendants).toEqual([]);
799+
});
800+
801+
748802
});

0 commit comments

Comments
 (0)