Skip to content

Commit 3b90567

Browse files
committed
feat: expand subsequently function (#287)
1 parent eaedac5 commit 3b90567

File tree

4 files changed

+114
-0
lines changed

4 files changed

+114
-0
lines changed

packages/core/src/environmentActions/EnvironmentActionsProvider.tsx

+17
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,21 @@ export const EnvironmentActionsProvider = React.forwardRef<
171171
[items, onPrimaryAction]
172172
);
173173

174+
const expandSubsequently = useCallback(
175+
async (treeId: string, itemIds: TreeItemIndex[]) => {
176+
const [current, ...rest] = itemIds;
177+
await waitFor(() => !!itemsRef.current?.[current]).then(() => {
178+
const item = itemsRef.current[current];
179+
if (!item) {
180+
return;
181+
}
182+
onExpandItem?.(item, treeId);
183+
expandSubsequently(treeId, rest);
184+
});
185+
},
186+
[itemsRef, onExpandItem]
187+
);
188+
174189
const expandAll = useCallback(
175190
async (treeId: string) => {
176191
await recursiveExpand(trees[treeId].rootItem, itemsRef, item =>
@@ -204,6 +219,7 @@ export const EnvironmentActionsProvider = React.forwardRef<
204219
toggleItemSelectStatus,
205220
invokePrimaryAction,
206221
expandAll,
222+
expandSubsequently,
207223
collapseAll,
208224
abortProgrammaticDrag,
209225
completeProgrammaticDrag,
@@ -224,6 +240,7 @@ export const EnvironmentActionsProvider = React.forwardRef<
224240
toggleItemSelectStatus,
225241
invokePrimaryAction,
226242
expandAll,
243+
expandSubsequently,
227244
collapseAll,
228245
abortProgrammaticDrag,
229246
completeProgrammaticDrag,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import { Meta } from '@storybook/react';
2+
import React, { useCallback, useMemo, useRef, useState } from 'react';
3+
import { longTree } from 'demodata';
4+
import { UncontrolledTreeEnvironment } from '../uncontrolledEnvironment/UncontrolledTreeEnvironment';
5+
import { StaticTreeDataProvider } from '../uncontrolledEnvironment/StaticTreeDataProvider';
6+
import { Tree } from '../tree/Tree';
7+
import { TreeItemIndex, TreeRef } from '../types';
8+
9+
export default {
10+
title: 'Core/Finding Items',
11+
} as Meta;
12+
13+
export const CustomFinder = () => {
14+
const [search, setSearch] = useState('');
15+
const tree = useRef<TreeRef>(null);
16+
17+
const dataProvider = useMemo(
18+
() =>
19+
new StaticTreeDataProvider(longTree.items, (item, data) => ({
20+
...item,
21+
data,
22+
})),
23+
[]
24+
);
25+
26+
const findItemPath = useCallback(
27+
async (search: string, searchRoot: TreeItemIndex = 'root') => {
28+
const item = await dataProvider.getTreeItem(searchRoot);
29+
if (item.data.toLowerCase().includes(search.toLowerCase())) {
30+
return [item.index];
31+
}
32+
const searchedItems = await Promise.all(
33+
item.children?.map(child => findItemPath(search, child)) ?? []
34+
);
35+
const result = searchedItems.find(item => item !== null);
36+
if (!result) {
37+
return null;
38+
}
39+
return [item.index, ...result];
40+
},
41+
[dataProvider]
42+
);
43+
44+
const find = useCallback(
45+
e => {
46+
e.preventDefault();
47+
if (search) {
48+
findItemPath(search).then(path => {
49+
if (path) {
50+
tree.current
51+
?.expandSubsequently(path.slice(0, path.length - 1))
52+
.then(() => {
53+
tree.current?.selectItems([path[path.length - 1]]);
54+
tree.current?.focusItem(path[path.length - 1]);
55+
});
56+
}
57+
});
58+
}
59+
},
60+
[findItemPath, search]
61+
);
62+
63+
return (
64+
<>
65+
<form onSubmit={find}>
66+
<input
67+
value={search}
68+
onChange={e => setSearch(e.target.value)}
69+
placeholder="Search..."
70+
/>
71+
<button type="submit">Find item</button>
72+
</form>
73+
<UncontrolledTreeEnvironment<string>
74+
dataProvider={dataProvider}
75+
getItemTitle={item => item.data}
76+
viewState={{
77+
'tree-1': {},
78+
}}
79+
>
80+
<Tree
81+
treeId="tree-1"
82+
rootItem="root"
83+
treeLabel="Tree Example"
84+
ref={tree}
85+
/>
86+
</UncontrolledTreeEnvironment>
87+
</>
88+
);
89+
};

packages/core/src/treeActions/TreeActionsProvider.tsx

+3
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ export const TreeActionsProvider = React.forwardRef<
8585
collapseAll(): void {
8686
envActions.collapseAll(tree.treeId);
8787
},
88+
expandSubsequently(itemIds: TreeItemIndex[]): Promise<void> {
89+
return envActions.expandSubsequently(tree.treeId, itemIds);
90+
},
8891
}),
8992
[envActions, tree]
9093
);

packages/core/src/types.ts

+5
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,10 @@ export interface TreeEnvironmentChangeActions {
233233
moveProgrammaticDragPositionDown: () => void;
234234
expandAll: (treeId: string) => void;
235235
collapseAll: (treeId: string) => void;
236+
expandSubsequently: (
237+
treeId: string,
238+
itemIds: TreeItemIndex[]
239+
) => Promise<void>;
236240
}
237241

238242
export type TreeEnvironmentActionsContextProps = TreeEnvironmentChangeActions;
@@ -389,6 +393,7 @@ export interface TreeChangeActions {
389393
abortSearch: () => void;
390394
expandAll: () => void;
391395
collapseAll: () => void;
396+
expandSubsequently: (itemIds: TreeItemIndex[]) => Promise<void>;
392397
}
393398

394399
export type TreeChangeActionsContextProps = TreeChangeActions;

0 commit comments

Comments
 (0)