Skip to content

Commit ccfa7aa

Browse files
committed
feat: shouldRenderChildren prop (#333)
1 parent e83d48c commit ccfa7aa

File tree

5 files changed

+83
-4
lines changed

5 files changed

+83
-4
lines changed

next-release-notes.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
- Add `setDomFocus` argument to focus-item methods to provide an escape hatch to set the focus state of an item in RCT
44
without updating the DOM focus. This defaults to true in all existing methods to maintain the current behavior if
5-
it is absent.
5+
it is absent. (#336)
6+
- Allow customizing when a subtree is rendered or not with the new `shouldRenderChildren` prop. This can be used to
7+
create opening and closing animations on subtrees. (#333)
68

79
### Bug Fixes
810

packages/core/src/stories/BasicExamples.stories.tsx

+64
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { Tree } from '../tree/Tree';
77
import { StaticTreeDataProvider } from '../uncontrolledEnvironment/StaticTreeDataProvider';
88
import { UncontrolledTreeEnvironment } from '../uncontrolledEnvironment/UncontrolledTreeEnvironment';
99
import { buildTestTree } from '../../test/helpers';
10+
import { TreeItemIndex } from '../types';
1011

1112
export default {
1213
title: 'Core/Basic Examples',
@@ -556,3 +557,66 @@ export const NavigateAway = () => {
556557
</UncontrolledTreeEnvironment>
557558
);
558559
};
560+
561+
export const AnimatedExpandingAndCollapsing = () => {
562+
const [openingItem, setOpeningItem] = useState<TreeItemIndex | undefined>();
563+
const [closingItem, setClosingItem] = useState<TreeItemIndex | undefined>();
564+
return (
565+
<UncontrolledTreeEnvironment<string>
566+
dataProvider={
567+
new StaticTreeDataProvider(longTree.items, (item, data) => ({
568+
...item,
569+
data,
570+
}))
571+
}
572+
getItemTitle={item => item.data}
573+
shouldRenderChildren={(item, context) =>
574+
context.isExpanded ||
575+
closingItem === item.index ||
576+
openingItem === item.index
577+
}
578+
onExpandItem={item => {
579+
setOpeningItem(item.index);
580+
setTimeout(() => {
581+
setOpeningItem(undefined);
582+
});
583+
}}
584+
onCollapseItem={item => {
585+
setClosingItem(item.index);
586+
setTimeout(() => {
587+
setClosingItem(undefined);
588+
}, 500);
589+
}}
590+
viewState={{
591+
'tree-1': {},
592+
}}
593+
renderItemsContainer={({ children, containerProps, parentId }) => (
594+
<div
595+
style={{
596+
overflow: 'hidden',
597+
}}
598+
>
599+
<ul
600+
{...containerProps}
601+
className="rct-tree-items-container"
602+
style={{
603+
transition: 'all 500ms',
604+
maxHeight:
605+
parentId === openingItem || parentId === closingItem
606+
? 0
607+
: '999999px',
608+
marginTop:
609+
parentId === closingItem || parentId === openingItem
610+
? '-100%'
611+
: '0',
612+
}}
613+
>
614+
{children}
615+
</ul>
616+
</div>
617+
)}
618+
>
619+
<Tree treeId="tree-1" rootItem="root" treeLabel="Tree Example" />
620+
</UncontrolledTreeEnvironment>
621+
);
622+
};

packages/core/src/treeItem/TreeItemElement.tsx

+5-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,11 @@ export const TreeItemElement = (props: {
3232
return null as any;
3333
}
3434

35-
const children = item.isFolder && isExpanded && item.children && (
35+
const shouldRenderChildren =
36+
environment.shouldRenderChildren?.(item, renderContext) ??
37+
(item.isFolder && isExpanded);
38+
39+
const children = item.children && shouldRenderChildren && (
3640
<TreeItemChildren depth={props.depth + 1} parentId={props.itemIndex}>
3741
{item.children}
3842
</TreeItemChildren>

packages/core/src/treeItem/useTreeItemRenderContext.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import { HTMLProps, useMemo } from 'react';
2-
import { TreeItem, TreeItemActions, TreeItemRenderFlags } from '../types';
2+
import {
3+
TreeItem,
4+
TreeItemActions,
5+
TreeItemRenderContext,
6+
TreeItemRenderFlags,
7+
} from '../types';
38
import { defaultMatcher } from '../search/defaultMatcher';
49
import { useTree } from '../tree/Tree';
510
import { useTreeEnvironment } from '../controlledEnvironment/ControlledTreeEnvironment';
@@ -37,7 +42,7 @@ export const useTreeItemRenderContext = (item?: TreeItem) => {
3742
item && environment.viewState[treeId]?.expandedItems?.includes(item.index);
3843
const isRenaming = item && renamingItem === item.index;
3944

40-
return useMemo(() => {
45+
return useMemo<TreeItemRenderContext | undefined>(() => {
4146
if (!item) {
4247
return undefined;
4348
}

packages/core/src/types.ts

+4
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,10 @@ export interface TreeCapabilities<T = any, C extends string = never> {
178178
itemTitle: string
179179
) => boolean;
180180
showLiveDescription?: boolean;
181+
shouldRenderChildren?: (
182+
item: TreeItem<T>,
183+
context: TreeItemRenderContext<C>
184+
) => boolean;
181185

182186
/**
183187
* See Issue #148 or the sample at

0 commit comments

Comments
 (0)