Skip to content

Commit 9b3655f

Browse files
fix(TreeView): treeview not passing props to treenode children (#19417)
* fix(TreeView): treeview not passing props to treenode children * fix: treenode to pass props to its child treenode * test: added test case for treenode wrapped in another component
1 parent a057797 commit 9b3655f

File tree

5 files changed

+98
-39
lines changed

5 files changed

+98
-39
lines changed

.all-contributorsrc

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1850,7 +1850,6 @@
18501850
]
18511851
},
18521852
{
1853-
18541853
"login": "murito",
18551854
"name": "Francisco Alcalá",
18561855
"avatar_url": "https://avatars.githubusercontent.com/u/2628140?v=4",
@@ -1894,6 +1893,15 @@
18941893
"contributions": [
18951894
"code"
18961895
]
1896+
},
1897+
{
1898+
"login": "Gopi-Agasthia-S-005CIU744",
1899+
"name": "Gopi-Agasthia-S-005CIU744",
1900+
"avatar_url": "https://avatars.githubusercontent.com/u/196181829?v=4",
1901+
"profile": "https://github.com/Gopi-Agasthia-S-005CIU744",
1902+
"contributions": [
1903+
"code"
1904+
]
18971905
}
18981906
],
18991907
"commitConvention": "none"

README.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -336,16 +336,14 @@ check out our [Contributing Guide](/.github/CONTRIBUTING.md) and our
336336
<td align="center"><a href="https://github.com/maisonsmd"><img src="https://avatars.githubusercontent.com/u/16435155?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Son H. Mai (Mason)</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=maisonsmd" title="Code">💻</a></td>
337337
<td align="center"><a href="https://github.com/warrenmblood"><img src="https://avatars.githubusercontent.com/u/69060697?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Warren Blood</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=warrenmblood" title="Code">💻</a></td>
338338
<td align="center"><a href="https://github.com/vcherneny"><img src="https://avatars.githubusercontent.com/u/11604315?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Vlad Cherneny</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=vcherneny" title="Code">💻</a></td>
339+
<td align="center"><a href="https://github.com/murito"><img src="https://avatars.githubusercontent.com/u/2628140?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Francisco Alcalá</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=murito" title="Code">💻</a></td>
339340
<td align="center"><a href="https://github.com/dkaushik95"><img src="https://avatars.githubusercontent.com/u/8481567?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dishant Kaushik</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=dkaushik95" title="Code">💻</a></td>
340-
<td align="center"><a href="https://github.com/jose-biescas"><img src="https://avatars.githubusercontent.com/u/188625806?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jose Biescas</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=jose-biescas" title="Code">💻</a></td>
341341
</tr>
342342
<tr>
343-
<td align="center"><a href="https://github.com/murito"><img src="https://avatars.githubusercontent.com/u/2628140?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Francisco Alcalá</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=murito" title="Code">💻</a></td>
344343
<td align="center"><a href="https://www.linkedin.com/in/sujithcs"><img src="https://avatars.githubusercontent.com/u/43125517?v=4?s=100" width="100px;" alt=""/><br /><sub><b>SUJITH C S</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=Code-Suji" title="Code">💻</a></td>
345-
</tr>
346-
<tr>
347344
<td align="center"><a href="https://github.com/mariyageorge01"><img src="https://avatars.githubusercontent.com/u/166684108?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mariya George</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=mariyageorge01" title="Code">💻</a></td>
348345
<td align="center"><a href="https://github.com/sojinantony01"><img src="https://avatars.githubusercontent.com/u/29255847?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sojin antony</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=sojinantony01" title="Code">💻</a></td>
346+
<td align="center"><a href="https://github.com/Gopi-Agasthia-S-005CIU744"><img src="https://avatars.githubusercontent.com/u/196181829?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Gopi-Agasthia-S-005CIU744</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=Gopi-Agasthia-S-005CIU744" title="Code">💻</a></td>
349347
</tr>
350348
</table>
351349

packages/react/src/components/TreeView/TreeNode.tsx

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -164,22 +164,36 @@ const TreeNode = React.forwardRef<HTMLElement, TreeNodeProps>(
164164
}
165165
};
166166

167-
const nodesWithProps = React.Children.map(children, (node) => {
168-
if (React.isValidElement(node)) {
169-
return React.cloneElement(node, {
170-
active,
171-
depth: depth + 1,
172-
disabled:
173-
disabled || (node as ReactElement<TreeNodeProps>).props.disabled,
174-
onTreeSelect,
175-
onNodeFocusEvent,
176-
selected,
177-
tabIndex:
178-
(!(node as ReactElement<TreeNodeProps>).props.disabled && -1) ||
179-
null,
180-
} as TreeNodeProps);
181-
}
182-
});
167+
function enhanceTreeNodes(children: React.ReactNode): React.ReactNode {
168+
return React.Children.map(children, (node) => {
169+
if (!React.isValidElement(node)) return node;
170+
171+
const isTreeNode = (node.type as any).displayName === 'TreeNode';
172+
173+
if (isTreeNode) {
174+
return React.cloneElement(node, {
175+
active,
176+
depth: depth + 1,
177+
disabled:
178+
disabled || (node as ReactElement<TreeNodeProps>).props.disabled,
179+
onTreeSelect,
180+
onNodeFocusEvent,
181+
selected,
182+
tabIndex: (node as ReactElement<TreeNodeProps>).props.disabled
183+
? null
184+
: -1,
185+
} as TreeNodeProps);
186+
}
187+
188+
const newChildren = enhanceTreeNodes((node.props as any).children);
189+
return React.cloneElement(node as React.ReactElement<any>, {
190+
children: newChildren,
191+
});
192+
});
193+
}
194+
195+
const nodesWithProps = enhanceTreeNodes(children);
196+
183197
const isActive = active === id;
184198
const isSelected = selected.includes(id);
185199
const treeNodeClasses = classNames(className, `${prefix}--tree-node`, {

packages/react/src/components/TreeView/TreeView-test.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,29 @@ describe('TreeView', () => {
5757
expect(within(nodeChild).getByText('Node 2')).toBeInTheDocument();
5858
});
5959

60+
it('should render children as expected when treenode is wrapped in a component', () => {
61+
render(
62+
<TreeView label="Tree View">
63+
<div>
64+
<TreeNode isExpanded={true} data-testid="Node 1" label="Node 1">
65+
<div>
66+
<TreeNode data-testid="Node 2" label="Node 2" />
67+
</div>
68+
</TreeNode>
69+
</div>
70+
</TreeView>
71+
);
72+
73+
const nodeParent = screen.getByTestId('Node 1');
74+
const nodeChild = screen.getByTestId('Node 2');
75+
76+
expect(nodeParent).toHaveClass(`${prefix}--tree-parent-node`);
77+
expect(nodeChild).toHaveClass(`${prefix}--tree-leaf-node`);
78+
79+
expect(within(nodeParent).getByText('Node 1')).toBeInTheDocument();
80+
expect(within(nodeChild).getByText('Node 2')).toBeInTheDocument();
81+
});
82+
6083
it('should render children as expected when using dot syntax', () => {
6184
render(
6285
<TreeView label="Tree View">

packages/react/src/components/TreeView/TreeView.tsx

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -182,24 +182,40 @@ const TreeView: TreeViewComponent = ({
182182
}
183183

184184
let focusTarget = false;
185-
const nodesWithProps = React.Children.map(children, (_node) => {
186-
const node = _node as React.ReactElement<TreeNodeProps>;
187-
const sharedNodeProps: Partial<TreeNodeProps> = {
188-
active,
189-
depth: 0,
190-
onNodeFocusEvent: handleFocusEvent,
191-
onTreeSelect: handleTreeSelect,
192-
selected,
193-
tabIndex: (!node.props.disabled && -1) || undefined,
194-
};
195-
if (!focusTarget && !node.props.disabled) {
196-
sharedNodeProps.tabIndex = 0;
197-
focusTarget = true;
198-
}
199-
if (React.isValidElement(node)) {
200-
return React.cloneElement(node, sharedNodeProps);
201-
}
202-
});
185+
function enhanceTreeNodes(children: React.ReactNode): React.ReactNode {
186+
return React.Children.map(children, (child) => {
187+
if (!React.isValidElement(child)) return child;
188+
189+
const isTreeNode = (child.type as any).displayName === 'TreeNode';
190+
191+
if (isTreeNode) {
192+
const node = child as React.ReactElement<TreeNodeProps>;
193+
194+
const sharedNodeProps: Partial<TreeNodeProps> = {
195+
active,
196+
depth: 0,
197+
onNodeFocusEvent: handleFocusEvent,
198+
onTreeSelect: handleTreeSelect,
199+
selected,
200+
tabIndex: node.props.disabled ? undefined : -1,
201+
};
202+
203+
if (!focusTarget && !node.props.disabled) {
204+
sharedNodeProps.tabIndex = 0;
205+
focusTarget = true;
206+
}
207+
208+
return React.cloneElement(child, sharedNodeProps);
209+
}
210+
211+
const newChildren = enhanceTreeNodes((child.props as any).children);
212+
return React.cloneElement(child as React.ReactElement<any>, {
213+
children: newChildren,
214+
});
215+
});
216+
}
217+
218+
const nodesWithProps = enhanceTreeNodes(children);
203219

204220
function handleKeyDown(event) {
205221
event.stopPropagation();

0 commit comments

Comments
 (0)