Skip to content

Commit b68937b

Browse files
authored
Enhance TreeApi with getSelectedLeafNodePaths and related methods and release version patch (#279)
1 parent b3bba6b commit b68937b

File tree

17 files changed

+928
-81
lines changed

17 files changed

+928
-81
lines changed
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import * as React from 'react';
2+
3+
import {
4+
DataSourceApi,
5+
InfiniteTableColumn,
6+
TreeDataSource,
7+
TreeGrid,
8+
} from '@infinite-table/infinite-react';
9+
10+
export type FileSystemNode = {
11+
name: string;
12+
type: 'file' | 'folder';
13+
children?: FileSystemNode[] | null;
14+
sizeKB?: number;
15+
id: string;
16+
collapsed?: boolean;
17+
};
18+
19+
export const nodes: FileSystemNode[] = [
20+
{
21+
name: 'Documents',
22+
type: 'folder',
23+
id: '1',
24+
children: [
25+
{
26+
name: 'report.doc',
27+
type: 'file',
28+
sizeKB: 100,
29+
id: '2',
30+
},
31+
{
32+
type: 'folder',
33+
name: 'pictures',
34+
id: '3',
35+
collapsed: true,
36+
children: [
37+
{
38+
name: 'mountain.jpg',
39+
type: 'file',
40+
sizeKB: 302,
41+
id: '5',
42+
},
43+
{
44+
name: 'mountain2.jpg',
45+
type: 'file',
46+
sizeKB: 352,
47+
id: '6',
48+
},
49+
],
50+
},
51+
{
52+
type: 'folder',
53+
name: 'misc',
54+
id: '4',
55+
collapsed: true,
56+
children: [
57+
{
58+
name: 'beach.jpg',
59+
type: 'file',
60+
sizeKB: 2024,
61+
id: '7',
62+
},
63+
],
64+
},
65+
{
66+
type: 'file',
67+
name: 'last.txt',
68+
id: '8',
69+
},
70+
],
71+
},
72+
];
73+
74+
const columns: Record<string, InfiniteTableColumn<FileSystemNode>> = {
75+
name: {
76+
field: 'name',
77+
defaultWidth: 300,
78+
renderTreeIcon: true,
79+
renderSelectionCheckBox: true,
80+
renderValue: ({ value, data }) => {
81+
return (
82+
<>
83+
{value} - {data!.id}
84+
</>
85+
);
86+
},
87+
},
88+
type: { field: 'type' },
89+
sizeKB: { field: 'sizeKB' },
90+
};
91+
92+
export default function DataTestPage() {
93+
const [dataSourceApi, setDataSourceApi] =
94+
React.useState<DataSourceApi<FileSystemNode> | null>(null);
95+
return (
96+
<React.StrictMode>
97+
<button onClick={() => dataSourceApi!.treeApi.selectAll()}>
98+
Select all
99+
</button>
100+
<TreeDataSource<FileSystemNode>
101+
onReady={setDataSourceApi}
102+
data={nodes}
103+
primaryKey="id"
104+
nodesKey="children"
105+
defaultTreeSelection={{
106+
defaultSelection: true,
107+
deselectedPaths: [['1', '3']],
108+
selectedPaths: [['1', '3', '6']],
109+
}}
110+
>
111+
<TreeGrid<FileSystemNode>
112+
wrapRowsHorizontally
113+
domProps={{
114+
style: {
115+
margin: '5px',
116+
height: 900,
117+
border: '1px solid gray',
118+
position: 'relative',
119+
},
120+
}}
121+
columns={columns}
122+
/>
123+
</TreeDataSource>
124+
</React.StrictMode>
125+
);
126+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { test, expect } from '@testing';
2+
3+
export default test.describe('TreeApi', () => {
4+
test('getSelectedLeafNodePaths works', async ({ page, apiModel }) => {
5+
await page.waitForInfinite();
6+
7+
const paths = await apiModel.evaluateTreeApi((treeApi) => {
8+
return treeApi.getSelectedLeafNodePaths();
9+
});
10+
11+
expect(paths).toEqual([
12+
['1', '2'],
13+
['1', '3', '6'],
14+
['1', '4', '7'],
15+
['1', '8'],
16+
]);
17+
});
18+
});
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
import {
2+
DataSourceApi,
3+
InfiniteTableColumn,
4+
TreeDataSource,
5+
TreeGrid,
6+
TreeSelectionValue,
7+
} from '@infinite-table/infinite-react';
8+
import { useState } from 'react';
9+
10+
type FileSystemNode = {
11+
id: string;
12+
name: string;
13+
children?: FileSystemNode[];
14+
};
15+
const nodes: FileSystemNode[] = [
16+
{
17+
id: '1',
18+
name: 'Documents',
19+
children: [
20+
{
21+
id: '10',
22+
name: 'Private',
23+
children: [
24+
{
25+
id: '100',
26+
name: 'Report.docx',
27+
},
28+
{
29+
id: '101',
30+
name: 'Vacation.docx',
31+
},
32+
{
33+
id: '102',
34+
name: 'CV.pdf',
35+
},
36+
],
37+
},
38+
],
39+
},
40+
{
41+
id: '2',
42+
name: 'Desktop',
43+
children: [
44+
{
45+
id: '20',
46+
name: 'unknown.txt',
47+
},
48+
],
49+
},
50+
{
51+
id: '3',
52+
name: 'Media',
53+
children: [
54+
{
55+
id: '30',
56+
name: 'Music',
57+
},
58+
{
59+
id: '31',
60+
name: 'Videos',
61+
children: [
62+
{
63+
id: '310',
64+
name: 'Vacation.mp4',
65+
},
66+
{
67+
id: '311',
68+
name: 'Youtube',
69+
children: [
70+
{
71+
id: '3110',
72+
name: 'Infinity',
73+
},
74+
{
75+
id: '3111',
76+
name: 'Infinity 2',
77+
},
78+
],
79+
},
80+
],
81+
},
82+
],
83+
},
84+
];
85+
86+
const columns: Record<string, InfiniteTableColumn<FileSystemNode>> = {
87+
name: {
88+
field: 'name',
89+
header: 'Name',
90+
defaultWidth: 500,
91+
renderValue: ({ value, rowInfo }) => {
92+
return (
93+
<div style={{ color: 'red', display: 'inline-block' }}>
94+
{rowInfo.id} - {value}
95+
</div>
96+
);
97+
},
98+
renderTreeIcon: true,
99+
renderSelectionCheckBox: true,
100+
},
101+
};
102+
103+
const defaultTreeSelection: TreeSelectionValue = {
104+
defaultSelection: false,
105+
selectedPaths: [['3']],
106+
deselectedPaths: [['3', '31', '311', '3110']],
107+
};
108+
109+
export default function App() {
110+
const [dataSourceApi, setDataSourceApi] =
111+
useState<DataSourceApi<FileSystemNode> | null>();
112+
113+
return (
114+
<>
115+
<TreeDataSource
116+
onReady={setDataSourceApi}
117+
nodesKey="children"
118+
primaryKey="id"
119+
data={dataSource}
120+
defaultTreeSelection={defaultTreeSelection}
121+
selectionMode="multi-row"
122+
onTreeSelectionChange={(e, { treeSelectionState }) => {
123+
console.log(
124+
'onTreeSelectionChange',
125+
e,
126+
treeSelectionState.getSelectedLeafNodePaths(),
127+
);
128+
}}
129+
>
130+
<div
131+
style={{
132+
color: 'var(--infinite-cell-color)',
133+
padding: 10,
134+
display: 'flex',
135+
gap: 10,
136+
}}
137+
>
138+
<button
139+
onClick={() => {
140+
dataSourceApi!.treeApi.selectAll();
141+
}}
142+
>
143+
Select all
144+
</button>
145+
<button
146+
onClick={() => {
147+
dataSourceApi!.treeApi.deselectAll();
148+
}}
149+
>
150+
Deselect all
151+
</button>
152+
</div>
153+
154+
<TreeGrid columns={columns} domProps={{ style: { height: '100%' } }} />
155+
</TreeDataSource>
156+
</>
157+
);
158+
}
159+
160+
const dataSource = () => {
161+
return Promise.resolve(nodes);
162+
};
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { test, expect } from '@testing';
2+
3+
export default test.describe('TreeSelectionProp', () => {
4+
test('when defined, makes selectionMode default to multi-row', async ({
5+
page,
6+
}) => {
7+
await page.waitForInfinite();
8+
9+
const headerCheckbox = await page.locator(
10+
'.InfiniteHeader input[type="checkbox"]',
11+
);
12+
expect(
13+
await headerCheckbox?.evaluate((el) => {
14+
return {
15+
checked: (el as HTMLInputElement).checked,
16+
indeterminate: (el as HTMLInputElement).indeterminate,
17+
};
18+
}),
19+
).toEqual({ checked: false, indeterminate: true });
20+
});
21+
});

0 commit comments

Comments
 (0)