@instructure/ui-tree-browser 11.6.0 → 11.6.1-snapshot-129
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -288
- package/es/TreeBrowser/{TreeButton → v1/TreeButton}/index.js +2 -2
- package/es/TreeBrowser/{TreeCollection → v1/TreeCollection}/index.js +1 -1
- package/es/TreeBrowser/{TreeNode → v1/TreeNode}/index.js +2 -2
- package/es/TreeBrowser/{index.js → v1/index.js} +1 -1
- package/es/TreeBrowser/v2/TreeBrowserContext.js +39 -0
- package/es/TreeBrowser/v2/TreeButton/index.js +202 -0
- package/es/TreeBrowser/v2/TreeButton/props.js +26 -0
- package/es/TreeBrowser/v2/TreeButton/styles.js +306 -0
- package/es/TreeBrowser/v2/TreeCollection/index.js +367 -0
- package/es/TreeBrowser/v2/TreeCollection/props.js +26 -0
- package/es/TreeBrowser/v2/TreeCollection/styles.js +143 -0
- package/es/TreeBrowser/v2/TreeNode/index.js +156 -0
- package/es/{index.js → TreeBrowser/v2/TreeNode/props.js} +3 -4
- package/es/TreeBrowser/v2/index.js +347 -0
- package/es/TreeBrowser/v2/props.js +35 -0
- package/es/TreeBrowser/v2/styles.js +71 -0
- package/es/exports/a.js +27 -0
- package/es/exports/b.js +27 -0
- package/lib/TreeBrowser/{TreeButton → v1/TreeButton}/index.js +3 -3
- package/lib/TreeBrowser/{TreeCollection → v1/TreeCollection}/index.js +1 -1
- package/lib/TreeBrowser/{TreeNode → v1/TreeNode}/index.js +3 -3
- package/lib/TreeBrowser/{index.js → v1/index.js} +3 -3
- package/lib/TreeBrowser/v2/TreeBrowserContext.js +44 -0
- package/lib/TreeBrowser/v2/TreeButton/index.js +208 -0
- package/lib/TreeBrowser/v2/TreeButton/props.js +31 -0
- package/lib/TreeBrowser/v2/TreeButton/styles.js +312 -0
- package/lib/TreeBrowser/v2/TreeCollection/index.js +372 -0
- package/lib/TreeBrowser/v2/TreeCollection/props.js +31 -0
- package/lib/TreeBrowser/v2/TreeCollection/styles.js +149 -0
- package/lib/TreeBrowser/v2/TreeNode/index.js +162 -0
- package/lib/TreeBrowser/v2/TreeNode/props.js +31 -0
- package/lib/TreeBrowser/v2/index.js +353 -0
- package/lib/TreeBrowser/v2/props.js +40 -0
- package/lib/TreeBrowser/v2/styles.js +77 -0
- package/lib/{index.js → exports/a.js} +5 -5
- package/lib/exports/b.js +33 -0
- package/package.json +40 -18
- package/src/TreeBrowser/{TreeButton → v1/TreeButton}/index.tsx +2 -2
- package/src/TreeBrowser/{TreeCollection → v1/TreeCollection}/index.tsx +1 -1
- package/src/TreeBrowser/{TreeNode → v1/TreeNode}/index.tsx +2 -2
- package/src/TreeBrowser/{index.tsx → v1/index.tsx} +1 -1
- package/src/TreeBrowser/v2/README.md +712 -0
- package/src/TreeBrowser/v2/TreeBrowserContext.ts +53 -0
- package/src/TreeBrowser/v2/TreeButton/index.tsx +210 -0
- package/src/TreeBrowser/v2/TreeButton/props.ts +95 -0
- package/src/TreeBrowser/v2/TreeButton/styles.ts +331 -0
- package/src/TreeBrowser/v2/TreeCollection/index.tsx +416 -0
- package/src/TreeBrowser/v2/TreeCollection/props.ts +88 -0
- package/src/TreeBrowser/v2/TreeCollection/styles.ts +157 -0
- package/src/TreeBrowser/v2/TreeNode/index.tsx +158 -0
- package/src/TreeBrowser/v2/TreeNode/props.ts +84 -0
- package/src/TreeBrowser/v2/index.tsx +438 -0
- package/src/TreeBrowser/v2/props.ts +245 -0
- package/src/TreeBrowser/v2/styles.ts +79 -0
- package/src/exports/a.ts +32 -0
- package/src/exports/b.ts +32 -0
- package/tsconfig.build.tsbuildinfo +1 -1
- package/types/TreeBrowser/v1/TreeBrowserContext.d.ts.map +1 -0
- package/types/TreeBrowser/v1/TreeButton/index.d.ts.map +1 -0
- package/types/TreeBrowser/v1/TreeButton/props.d.ts.map +1 -0
- package/types/TreeBrowser/v1/TreeButton/styles.d.ts.map +1 -0
- package/types/TreeBrowser/v1/TreeButton/theme.d.ts.map +1 -0
- package/types/TreeBrowser/{TreeCollection → v1/TreeCollection}/index.d.ts +1 -1
- package/types/TreeBrowser/v1/TreeCollection/index.d.ts.map +1 -0
- package/types/TreeBrowser/v1/TreeCollection/props.d.ts.map +1 -0
- package/types/TreeBrowser/v1/TreeCollection/styles.d.ts.map +1 -0
- package/types/TreeBrowser/v1/TreeCollection/theme.d.ts.map +1 -0
- package/types/TreeBrowser/v1/TreeNode/index.d.ts.map +1 -0
- package/types/TreeBrowser/v1/TreeNode/props.d.ts.map +1 -0
- package/types/TreeBrowser/v1/index.d.ts.map +1 -0
- package/types/TreeBrowser/v1/props.d.ts.map +1 -0
- package/types/TreeBrowser/v1/styles.d.ts.map +1 -0
- package/types/TreeBrowser/v1/theme.d.ts.map +1 -0
- package/types/TreeBrowser/v2/TreeBrowserContext.d.ts +24 -0
- package/types/TreeBrowser/v2/TreeBrowserContext.d.ts.map +1 -0
- package/types/TreeBrowser/v2/TreeButton/index.d.ts +44 -0
- package/types/TreeBrowser/v2/TreeButton/index.d.ts.map +1 -0
- package/types/TreeBrowser/v2/TreeButton/props.d.ts +37 -0
- package/types/TreeBrowser/v2/TreeButton/props.d.ts.map +1 -0
- package/types/TreeBrowser/v2/TreeButton/styles.d.ts +19 -0
- package/types/TreeBrowser/v2/TreeButton/styles.d.ts.map +1 -0
- package/types/TreeBrowser/v2/TreeCollection/index.d.ts +66 -0
- package/types/TreeBrowser/v2/TreeCollection/index.d.ts.map +1 -0
- package/types/TreeBrowser/v2/TreeCollection/props.d.ts +24 -0
- package/types/TreeBrowser/v2/TreeCollection/props.d.ts.map +1 -0
- package/types/TreeBrowser/v2/TreeCollection/styles.d.ts +18 -0
- package/types/TreeBrowser/v2/TreeCollection/styles.d.ts.map +1 -0
- package/types/TreeBrowser/v2/TreeNode/index.d.ts +41 -0
- package/types/TreeBrowser/v2/TreeNode/index.d.ts.map +1 -0
- package/types/TreeBrowser/v2/TreeNode/props.d.ts +25 -0
- package/types/TreeBrowser/v2/TreeNode/props.d.ts.map +1 -0
- package/types/TreeBrowser/v2/index.d.ts +70 -0
- package/types/TreeBrowser/v2/index.d.ts.map +1 -0
- package/types/TreeBrowser/v2/props.d.ts +163 -0
- package/types/TreeBrowser/v2/props.d.ts.map +1 -0
- package/types/TreeBrowser/v2/styles.d.ts +16 -0
- package/types/TreeBrowser/v2/styles.d.ts.map +1 -0
- package/types/exports/a.d.ts +9 -0
- package/types/exports/a.d.ts.map +1 -0
- package/types/exports/b.d.ts +9 -0
- package/types/exports/b.d.ts.map +1 -0
- package/src/index.ts +0 -32
- package/types/TreeBrowser/TreeBrowserContext.d.ts.map +0 -1
- package/types/TreeBrowser/TreeButton/index.d.ts.map +0 -1
- package/types/TreeBrowser/TreeButton/props.d.ts.map +0 -1
- package/types/TreeBrowser/TreeButton/styles.d.ts.map +0 -1
- package/types/TreeBrowser/TreeButton/theme.d.ts.map +0 -1
- package/types/TreeBrowser/TreeCollection/index.d.ts.map +0 -1
- package/types/TreeBrowser/TreeCollection/props.d.ts.map +0 -1
- package/types/TreeBrowser/TreeCollection/styles.d.ts.map +0 -1
- package/types/TreeBrowser/TreeCollection/theme.d.ts.map +0 -1
- package/types/TreeBrowser/TreeNode/index.d.ts.map +0 -1
- package/types/TreeBrowser/TreeNode/props.d.ts.map +0 -1
- package/types/TreeBrowser/index.d.ts.map +0 -1
- package/types/TreeBrowser/props.d.ts.map +0 -1
- package/types/TreeBrowser/styles.d.ts.map +0 -1
- package/types/TreeBrowser/theme.d.ts.map +0 -1
- package/types/index.d.ts +0 -9
- package/types/index.d.ts.map +0 -1
- /package/es/TreeBrowser/{TreeBrowserContext.js → v1/TreeBrowserContext.js} +0 -0
- /package/es/TreeBrowser/{TreeButton → v1/TreeButton}/props.js +0 -0
- /package/es/TreeBrowser/{TreeButton → v1/TreeButton}/styles.js +0 -0
- /package/es/TreeBrowser/{TreeButton → v1/TreeButton}/theme.js +0 -0
- /package/es/TreeBrowser/{TreeCollection → v1/TreeCollection}/props.js +0 -0
- /package/es/TreeBrowser/{TreeCollection → v1/TreeCollection}/styles.js +0 -0
- /package/es/TreeBrowser/{TreeCollection → v1/TreeCollection}/theme.js +0 -0
- /package/es/TreeBrowser/{TreeNode → v1/TreeNode}/props.js +0 -0
- /package/es/TreeBrowser/{props.js → v1/props.js} +0 -0
- /package/es/TreeBrowser/{styles.js → v1/styles.js} +0 -0
- /package/es/TreeBrowser/{theme.js → v1/theme.js} +0 -0
- /package/lib/TreeBrowser/{TreeBrowserContext.js → v1/TreeBrowserContext.js} +0 -0
- /package/lib/TreeBrowser/{TreeButton → v1/TreeButton}/props.js +0 -0
- /package/lib/TreeBrowser/{TreeButton → v1/TreeButton}/styles.js +0 -0
- /package/lib/TreeBrowser/{TreeButton → v1/TreeButton}/theme.js +0 -0
- /package/lib/TreeBrowser/{TreeCollection → v1/TreeCollection}/props.js +0 -0
- /package/lib/TreeBrowser/{TreeCollection → v1/TreeCollection}/styles.js +0 -0
- /package/lib/TreeBrowser/{TreeCollection → v1/TreeCollection}/theme.js +0 -0
- /package/lib/TreeBrowser/{TreeNode → v1/TreeNode}/props.js +0 -0
- /package/lib/TreeBrowser/{props.js → v1/props.js} +0 -0
- /package/lib/TreeBrowser/{styles.js → v1/styles.js} +0 -0
- /package/lib/TreeBrowser/{theme.js → v1/theme.js} +0 -0
- /package/src/TreeBrowser/{README.md → v1/README.md} +0 -0
- /package/src/TreeBrowser/{TreeBrowserContext.ts → v1/TreeBrowserContext.ts} +0 -0
- /package/src/TreeBrowser/{TreeButton → v1/TreeButton}/props.ts +0 -0
- /package/src/TreeBrowser/{TreeButton → v1/TreeButton}/styles.ts +0 -0
- /package/src/TreeBrowser/{TreeButton → v1/TreeButton}/theme.ts +0 -0
- /package/src/TreeBrowser/{TreeCollection → v1/TreeCollection}/props.ts +0 -0
- /package/src/TreeBrowser/{TreeCollection → v1/TreeCollection}/styles.ts +0 -0
- /package/src/TreeBrowser/{TreeCollection → v1/TreeCollection}/theme.ts +0 -0
- /package/src/TreeBrowser/{TreeNode → v1/TreeNode}/props.ts +0 -0
- /package/src/TreeBrowser/{props.ts → v1/props.ts} +0 -0
- /package/src/TreeBrowser/{styles.ts → v1/styles.ts} +0 -0
- /package/src/TreeBrowser/{theme.ts → v1/theme.ts} +0 -0
- /package/types/TreeBrowser/{TreeBrowserContext.d.ts → v1/TreeBrowserContext.d.ts} +0 -0
- /package/types/TreeBrowser/{TreeButton → v1/TreeButton}/index.d.ts +0 -0
- /package/types/TreeBrowser/{TreeButton → v1/TreeButton}/props.d.ts +0 -0
- /package/types/TreeBrowser/{TreeButton → v1/TreeButton}/styles.d.ts +0 -0
- /package/types/TreeBrowser/{TreeButton → v1/TreeButton}/theme.d.ts +0 -0
- /package/types/TreeBrowser/{TreeCollection → v1/TreeCollection}/props.d.ts +0 -0
- /package/types/TreeBrowser/{TreeCollection → v1/TreeCollection}/styles.d.ts +0 -0
- /package/types/TreeBrowser/{TreeCollection → v1/TreeCollection}/theme.d.ts +0 -0
- /package/types/TreeBrowser/{TreeNode → v1/TreeNode}/index.d.ts +0 -0
- /package/types/TreeBrowser/{TreeNode → v1/TreeNode}/props.d.ts +0 -0
- /package/types/TreeBrowser/{index.d.ts → v1/index.d.ts} +0 -0
- /package/types/TreeBrowser/{props.d.ts → v1/props.d.ts} +0 -0
- /package/types/TreeBrowser/{styles.d.ts → v1/styles.d.ts} +0 -0
- /package/types/TreeBrowser/{theme.d.ts → v1/theme.d.ts} +0 -0
|
@@ -0,0 +1,712 @@
|
|
|
1
|
+
---
|
|
2
|
+
describes: TreeBrowser
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
The `<TreeBrowser/>` component provides a keyboard accessible tree structure. The component expects
|
|
6
|
+
to receive a normalized data structure, examples can be seen at https://github.com/paularmstrong/normalizr.
|
|
7
|
+
|
|
8
|
+
### Size
|
|
9
|
+
|
|
10
|
+
```js
|
|
11
|
+
---
|
|
12
|
+
type: example
|
|
13
|
+
---
|
|
14
|
+
const Example = () => {
|
|
15
|
+
const [size, setSize] = useState('medium')
|
|
16
|
+
const sizes = ['small', 'medium', 'large']
|
|
17
|
+
|
|
18
|
+
const handleSizeSelect = (e, size) => {
|
|
19
|
+
setSize(size)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<>
|
|
24
|
+
<View display="block" margin="none none medium">
|
|
25
|
+
<RadioInputGroup
|
|
26
|
+
name="treeBrowserSize"
|
|
27
|
+
defaultValue="medium"
|
|
28
|
+
description={
|
|
29
|
+
<ScreenReaderContent>
|
|
30
|
+
TreeBrowser size selector
|
|
31
|
+
</ScreenReaderContent>
|
|
32
|
+
}
|
|
33
|
+
variant="toggle"
|
|
34
|
+
onChange={handleSizeSelect}
|
|
35
|
+
>
|
|
36
|
+
{sizes.map((size) => (
|
|
37
|
+
<RadioInput key={size} label={size} value={size} />
|
|
38
|
+
))}
|
|
39
|
+
</RadioInputGroup>
|
|
40
|
+
</View>
|
|
41
|
+
|
|
42
|
+
<TreeBrowser
|
|
43
|
+
size={size}
|
|
44
|
+
collections={{
|
|
45
|
+
1: {
|
|
46
|
+
id: 1,
|
|
47
|
+
name: 'Assignments',
|
|
48
|
+
collections: [2, 3],
|
|
49
|
+
items: [3],
|
|
50
|
+
descriptor: 'Class Assignments'
|
|
51
|
+
},
|
|
52
|
+
2: {
|
|
53
|
+
id: 2,
|
|
54
|
+
name: 'English Assignments',
|
|
55
|
+
collections: [4],
|
|
56
|
+
items: []
|
|
57
|
+
},
|
|
58
|
+
3: {
|
|
59
|
+
id: 3,
|
|
60
|
+
name: 'Math Assignments',
|
|
61
|
+
collections: [5],
|
|
62
|
+
items: [1, 2]
|
|
63
|
+
},
|
|
64
|
+
4: {
|
|
65
|
+
id: 4,
|
|
66
|
+
name: 'Reading Assignments',
|
|
67
|
+
collections: [],
|
|
68
|
+
items: [4]
|
|
69
|
+
},
|
|
70
|
+
5: { id: 5, name: 'Advanced Math Assignments', items: [5] }
|
|
71
|
+
}}
|
|
72
|
+
items={{
|
|
73
|
+
1: { id: 1, name: 'Addition Worksheet' },
|
|
74
|
+
2: { id: 2, name: 'Subtraction Worksheet' },
|
|
75
|
+
3: { id: 3, name: 'General Questions' },
|
|
76
|
+
4: { id: 4, name: 'Vogon Poetry' },
|
|
77
|
+
5: {
|
|
78
|
+
id: 5,
|
|
79
|
+
name: 'Bistromath',
|
|
80
|
+
descriptor: 'Explain the Bistromathic Drive'
|
|
81
|
+
}
|
|
82
|
+
}}
|
|
83
|
+
defaultExpanded={[1, 3]}
|
|
84
|
+
rootId={1}
|
|
85
|
+
/>
|
|
86
|
+
</>
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
render(<Example />)
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Managing State
|
|
94
|
+
|
|
95
|
+
`<TreeBrowser />` can be fully controlled. The following example uses the `onCollectionToggle` callback function to set the state. It then uses the `expanded` prop to configure which collections are open or closed.
|
|
96
|
+
|
|
97
|
+
```js
|
|
98
|
+
---
|
|
99
|
+
type: example
|
|
100
|
+
---
|
|
101
|
+
const Example = () => {
|
|
102
|
+
const [expanded, setExpanded] = useState([2])
|
|
103
|
+
|
|
104
|
+
const handleCollectionClick = (id, collection) => {
|
|
105
|
+
console.log(collection.id)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const handleCollectionToggle = (collection) => {
|
|
109
|
+
setExpanded((prevExpanded) => {
|
|
110
|
+
const newExpanded = [...prevExpanded]
|
|
111
|
+
const index = newExpanded.indexOf(collection.id)
|
|
112
|
+
|
|
113
|
+
if (!collection.expanded) {
|
|
114
|
+
newExpanded.splice(index, 1)
|
|
115
|
+
} else if (index < 0) {
|
|
116
|
+
newExpanded.push(collection.id)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return newExpanded
|
|
120
|
+
})
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return (
|
|
124
|
+
<TreeBrowser
|
|
125
|
+
variant="indent"
|
|
126
|
+
selectionType="single"
|
|
127
|
+
collections={{
|
|
128
|
+
1: { id: 1, name: 'Grade 1', collections: [2, 3, 6] },
|
|
129
|
+
2: {
|
|
130
|
+
id: 2,
|
|
131
|
+
name: 'Math Outcomes',
|
|
132
|
+
collections: [4],
|
|
133
|
+
items: [3, 4],
|
|
134
|
+
descriptor: '1 Group | 2 Outcomes'
|
|
135
|
+
},
|
|
136
|
+
3: {
|
|
137
|
+
id: 3,
|
|
138
|
+
name: 'Reading Outcome',
|
|
139
|
+
collections: [5],
|
|
140
|
+
items: [1, 2],
|
|
141
|
+
descriptor: '1 Group | 2 Outcomes'
|
|
142
|
+
},
|
|
143
|
+
4: {
|
|
144
|
+
id: 4,
|
|
145
|
+
name: 'Advanced Math',
|
|
146
|
+
items: [6],
|
|
147
|
+
descriptor: '1 Outcome'
|
|
148
|
+
},
|
|
149
|
+
5: {
|
|
150
|
+
id: 5,
|
|
151
|
+
name: 'Advanced Reading',
|
|
152
|
+
items: [5],
|
|
153
|
+
descriptor: '1 Group | 2 Outcomes'
|
|
154
|
+
},
|
|
155
|
+
6: {
|
|
156
|
+
id: 6,
|
|
157
|
+
name: 'Advanced Outcomes',
|
|
158
|
+
items: [5, 6],
|
|
159
|
+
descriptor: '2 Outcomes'
|
|
160
|
+
}
|
|
161
|
+
}}
|
|
162
|
+
items={{
|
|
163
|
+
1: { id: 1, name: 'Can read' },
|
|
164
|
+
2: { id: 2, name: 'Can write' },
|
|
165
|
+
3: { id: 3, name: 'Can add' },
|
|
166
|
+
4: { id: 4, name: 'Can subtract' },
|
|
167
|
+
5: { id: 5, name: 'Can read Shakespeare' },
|
|
168
|
+
6: { id: 6, name: 'Can do quantum physics' }
|
|
169
|
+
}}
|
|
170
|
+
showRootCollection={false}
|
|
171
|
+
rootId={1}
|
|
172
|
+
expanded={expanded}
|
|
173
|
+
onCollectionToggle={handleCollectionToggle}
|
|
174
|
+
onCollectionClick={handleCollectionClick}
|
|
175
|
+
/>
|
|
176
|
+
)
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
render(<Example />)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Customizing Icons
|
|
183
|
+
|
|
184
|
+
All of the `<TreeBrowser>` icons are customizable.
|
|
185
|
+
The following example sets custom icons for the expanded and collapsed state of the collections via `collectionIcon` and `collectionIconExpanded` and custom item icons via `itemIcon`.
|
|
186
|
+
|
|
187
|
+
```js
|
|
188
|
+
---
|
|
189
|
+
type: example
|
|
190
|
+
---
|
|
191
|
+
<TreeBrowser
|
|
192
|
+
collections={{
|
|
193
|
+
1: {
|
|
194
|
+
id: 1,
|
|
195
|
+
name: "Grades",
|
|
196
|
+
collections: [],
|
|
197
|
+
items: [1,2,3]
|
|
198
|
+
},
|
|
199
|
+
}}
|
|
200
|
+
items={{
|
|
201
|
+
1: { id: 1, name: "Sarah" },
|
|
202
|
+
2: { id: 2, name: "Jenny" },
|
|
203
|
+
3: { id: 3, name: "Juan" }
|
|
204
|
+
}}
|
|
205
|
+
defaultExpanded={[1]}
|
|
206
|
+
|
|
207
|
+
collectionIcon = {<BookCheckInstUIIcon />}
|
|
208
|
+
collectionIconExpanded = {XInstUIIcon}
|
|
209
|
+
itemIcon={() => <UserInstUIIcon />}
|
|
210
|
+
|
|
211
|
+
rootId={1}
|
|
212
|
+
size="large"
|
|
213
|
+
/>
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
#### Different icons for each item
|
|
217
|
+
|
|
218
|
+
One way do this is to use `getItemProps`. This function is called with the props for each item and returns new props you specify. These props are then passed to the item when it is rendered. In the following example, we override the `itemIcon` prop depending on the item name.
|
|
219
|
+
|
|
220
|
+
```js
|
|
221
|
+
---
|
|
222
|
+
type: example
|
|
223
|
+
---
|
|
224
|
+
<TreeBrowser
|
|
225
|
+
collections={{
|
|
226
|
+
1: {
|
|
227
|
+
id: 1,
|
|
228
|
+
name: "Saved",
|
|
229
|
+
collections: [],
|
|
230
|
+
items: [1,2,3]
|
|
231
|
+
},
|
|
232
|
+
}}
|
|
233
|
+
items={{
|
|
234
|
+
1: { id: 1, name: "Modules" },
|
|
235
|
+
2: { id: 2, name: "Videos" },
|
|
236
|
+
3: { id: 3, name: "Students" }
|
|
237
|
+
}}
|
|
238
|
+
defaultExpanded={[1]}
|
|
239
|
+
rootId={1}
|
|
240
|
+
size="large"
|
|
241
|
+
getItemProps={({ name, ...props }) => {
|
|
242
|
+
let itemIcon = <UserInstUIIcon />
|
|
243
|
+
|
|
244
|
+
if (name === 'Modules') {
|
|
245
|
+
itemIcon = <BoxesInstUIIcon />
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (name === 'Videos') {
|
|
249
|
+
itemIcon = <PlaySquareInstUIIcon />
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return {
|
|
253
|
+
...props, // Be sure to pass the rest of the props along
|
|
254
|
+
itemIcon,
|
|
255
|
+
name
|
|
256
|
+
}
|
|
257
|
+
}}
|
|
258
|
+
/>
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Another way to do it is to specify the `thumbnail` property in the `items` collection. This also overrides `itemIcon`.
|
|
262
|
+
|
|
263
|
+
```js
|
|
264
|
+
---
|
|
265
|
+
type: example
|
|
266
|
+
---
|
|
267
|
+
<TreeBrowser
|
|
268
|
+
collections={{
|
|
269
|
+
1: {
|
|
270
|
+
id: 1,
|
|
271
|
+
name: "Pandas",
|
|
272
|
+
collections: [],
|
|
273
|
+
items: [1,2,3]
|
|
274
|
+
},
|
|
275
|
+
}}
|
|
276
|
+
items={{
|
|
277
|
+
1: { id: 1, name: "Bao Bao", thumbnail: avatarSquare },
|
|
278
|
+
2: { id: 2, name: "Bei Bei" },
|
|
279
|
+
3: { id: 3, name: "Mei Xiang", thumbnail: avatarPortrait }
|
|
280
|
+
}}
|
|
281
|
+
defaultExpanded={[1]}
|
|
282
|
+
itemIcon={<UserInstUIIcon />}
|
|
283
|
+
rootId={1}
|
|
284
|
+
size="large"
|
|
285
|
+
/>
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### Rendering custom content in nodes
|
|
289
|
+
|
|
290
|
+
Using the `renderContent` property allows you to render custom content in the area where the text and descriptor are.
|
|
291
|
+
To meet a11y standards make sure to have the right contrast ratio on hovered and selected states; you can use the
|
|
292
|
+
`selected` and `focused` attributes in the given `props`.
|
|
293
|
+
|
|
294
|
+
```js
|
|
295
|
+
---
|
|
296
|
+
type: example
|
|
297
|
+
---
|
|
298
|
+
<TreeBrowser
|
|
299
|
+
collections={{
|
|
300
|
+
1: {
|
|
301
|
+
id: 1,
|
|
302
|
+
name: "Pandas",
|
|
303
|
+
collections: [],
|
|
304
|
+
items: [1, 2, 3]
|
|
305
|
+
},
|
|
306
|
+
}}
|
|
307
|
+
items={{
|
|
308
|
+
1: { id: 1, name: "Bao Bao" },
|
|
309
|
+
2: { id: 2, name: "Bei Bei" },
|
|
310
|
+
3: { id: 3, name: "Mei Xiang" }
|
|
311
|
+
}}
|
|
312
|
+
defaultExpanded={[1]}
|
|
313
|
+
itemIcon={<UserInstUIIcon />}
|
|
314
|
+
rootId={1}
|
|
315
|
+
size="large"
|
|
316
|
+
renderContent={(props)=> {
|
|
317
|
+
if (props.level > 1) {
|
|
318
|
+
return <div style={{ display: 'flex', alignItems: 'flex-end', padding: '0.6rem 0 0.6rem 1rem', color: 'darkorange' }}>
|
|
319
|
+
<span>{props.name}</span>
|
|
320
|
+
<Tag text="done" size="small" margin="0 xx-small 0 xx-small"/>
|
|
321
|
+
<Tag text="class A" size="small"/>
|
|
322
|
+
</div>
|
|
323
|
+
}
|
|
324
|
+
return <div style={{padding: '0.6rem 0 0.6rem 1rem', color: 'darkorange'}}>{props.name}</div>
|
|
325
|
+
}}
|
|
326
|
+
/>
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### Rendering custom items before and after nodes
|
|
330
|
+
|
|
331
|
+
An example of a `<TreeBrowser />` with a custom item after each collection.
|
|
332
|
+
|
|
333
|
+
When rendering custom interactive content (such as input fields), use the `hoverable` prop on `<TreeBrowser.Node />` to control the default hover behavior. Set it to `false` to disable hover effects while custom interactive elements are shown.
|
|
334
|
+
|
|
335
|
+
This example uses controlled selection (the `selection` prop with the `onSelectionChange` callback) to manage the selected state. Clicking the custom node clears the current selection by calling `setSelection('')`, ensuring a clean and predictable user experience.
|
|
336
|
+
|
|
337
|
+
```js
|
|
338
|
+
---
|
|
339
|
+
type: example
|
|
340
|
+
---
|
|
341
|
+
const Example = () => {
|
|
342
|
+
const [expanded, setExpanded] = useState(true)
|
|
343
|
+
const [hoveredLine, setHoveredLine] = useState(null)
|
|
344
|
+
const [selection, setSelection] = useState('')
|
|
345
|
+
const nodeRef = useRef(null)
|
|
346
|
+
|
|
347
|
+
const handleExpandToggle = useCallback((e, newExpandedState) => {
|
|
348
|
+
e.stopPropagation()
|
|
349
|
+
setExpanded(newExpandedState)
|
|
350
|
+
setSelection('')
|
|
351
|
+
nodeRef.current?.focus()
|
|
352
|
+
}, [])
|
|
353
|
+
|
|
354
|
+
const handleKeyPress = useCallback(
|
|
355
|
+
(e, newExpandedState) => {
|
|
356
|
+
if (e.code === 'Space' || e.code === 'Enter') {
|
|
357
|
+
e.preventDefault()
|
|
358
|
+
handleExpandToggle(e, newExpandedState)
|
|
359
|
+
}
|
|
360
|
+
},
|
|
361
|
+
[handleExpandToggle]
|
|
362
|
+
)
|
|
363
|
+
|
|
364
|
+
const renderInput = () => {
|
|
365
|
+
if (expanded) {
|
|
366
|
+
return (
|
|
367
|
+
<View
|
|
368
|
+
as="div"
|
|
369
|
+
padding="xx-small"
|
|
370
|
+
onFocus={(e) => e.stopPropagation()}
|
|
371
|
+
onClick={(e) => {
|
|
372
|
+
e.stopPropagation()
|
|
373
|
+
setSelection('')
|
|
374
|
+
}}
|
|
375
|
+
onMouseEnter={() => setHoveredLine('renderAfter')}
|
|
376
|
+
onMouseLeave={() => setHoveredLine(null)}
|
|
377
|
+
>
|
|
378
|
+
<TextInput
|
|
379
|
+
placeholder="Enter new group name"
|
|
380
|
+
display="inline-block"
|
|
381
|
+
width="12rem"
|
|
382
|
+
renderLabel=""
|
|
383
|
+
onKeyDown={(e) => e.stopPropagation()}
|
|
384
|
+
onFocus={() => setSelection('')}
|
|
385
|
+
/>
|
|
386
|
+
<IconButton
|
|
387
|
+
screenReaderLabel="Cancel"
|
|
388
|
+
onClick={(e) => handleExpandToggle(e, false)}
|
|
389
|
+
onKeyDown={(e) => handleKeyPress(e, false)}
|
|
390
|
+
margin="0 0 0 small"
|
|
391
|
+
>
|
|
392
|
+
<XInstUIIcon />
|
|
393
|
+
</IconButton>
|
|
394
|
+
<IconButton
|
|
395
|
+
screenReaderLabel="Add new group"
|
|
396
|
+
onClick={(e) => handleExpandToggle(e, false)}
|
|
397
|
+
onKeyDown={(e) => handleKeyPress(e, false)}
|
|
398
|
+
margin="0 0 0 small"
|
|
399
|
+
>
|
|
400
|
+
<CheckInstUIIcon />
|
|
401
|
+
</IconButton>
|
|
402
|
+
</View>
|
|
403
|
+
)
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
return <View as="div">Create New Group</View>
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
const renderNode = () => (
|
|
410
|
+
<TreeBrowser.Node
|
|
411
|
+
containerRef={(el) => (nodeRef.current = el)}
|
|
412
|
+
onClick={(e) => handleExpandToggle(e, !expanded)}
|
|
413
|
+
onKeyDown={(e) => handleKeyPress(e, !expanded)}
|
|
414
|
+
itemIcon={expanded ? '' : <PlusInstUIIcon />}
|
|
415
|
+
size="large"
|
|
416
|
+
hoverable={!expanded}
|
|
417
|
+
>
|
|
418
|
+
{renderInput()}
|
|
419
|
+
</TreeBrowser.Node>
|
|
420
|
+
)
|
|
421
|
+
|
|
422
|
+
return (
|
|
423
|
+
<TreeBrowser
|
|
424
|
+
selectionType="single"
|
|
425
|
+
selection={selection}
|
|
426
|
+
onSelectionChange={(newSelection) => setSelection(newSelection)}
|
|
427
|
+
size="large"
|
|
428
|
+
defaultExpanded={[1, 2]}
|
|
429
|
+
collections={{
|
|
430
|
+
1: {
|
|
431
|
+
id: 1,
|
|
432
|
+
name: 'Grade 1',
|
|
433
|
+
collections: [2]
|
|
434
|
+
},
|
|
435
|
+
2: {
|
|
436
|
+
id: 2,
|
|
437
|
+
name: 'Math Outcomes',
|
|
438
|
+
collections: [],
|
|
439
|
+
items: [1, 2],
|
|
440
|
+
descriptor: '1 Group | 2 Outcomes',
|
|
441
|
+
renderAfterItems: renderNode()
|
|
442
|
+
}
|
|
443
|
+
}}
|
|
444
|
+
items={{
|
|
445
|
+
1: { id: 1, name: 'Can add' },
|
|
446
|
+
2: { id: 2, name: 'Can subtract' }
|
|
447
|
+
}}
|
|
448
|
+
showRootCollection={true}
|
|
449
|
+
rootId={1}
|
|
450
|
+
/>
|
|
451
|
+
)
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
render(<Example />)
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
### Change the order of appearance of items and collections
|
|
458
|
+
|
|
459
|
+
By default, the order of collections and items depend on the order of `collections` and `items` array. We can override it by providing a `sortOrder` comparison function.
|
|
460
|
+
|
|
461
|
+
---
|
|
462
|
+
|
|
463
|
+
**NOTE**
|
|
464
|
+
|
|
465
|
+
This works with all collections and items of the TreeBrowser.
|
|
466
|
+
|
|
467
|
+
---
|
|
468
|
+
|
|
469
|
+
```js
|
|
470
|
+
---
|
|
471
|
+
type: example
|
|
472
|
+
---
|
|
473
|
+
const Example = () => {
|
|
474
|
+
const [size, setSize] = useState('medium')
|
|
475
|
+
const [sorted, setSorted] = useState(false)
|
|
476
|
+
|
|
477
|
+
const toggleSort = () => {
|
|
478
|
+
setSorted(!sorted)
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
return (
|
|
482
|
+
<>
|
|
483
|
+
<View display="block" margin="none none medium">
|
|
484
|
+
<FormFieldGroup description="Turn on/off sorting">
|
|
485
|
+
<Checkbox checked={sorted} label="Sort" onChange={toggleSort} />
|
|
486
|
+
</FormFieldGroup>
|
|
487
|
+
</View>
|
|
488
|
+
|
|
489
|
+
<TreeBrowser
|
|
490
|
+
size={size}
|
|
491
|
+
collections={{
|
|
492
|
+
1: {
|
|
493
|
+
id: 1,
|
|
494
|
+
name: 'Assignments',
|
|
495
|
+
collections: [3, 2],
|
|
496
|
+
items: [3],
|
|
497
|
+
descriptor: 'Class Assignments'
|
|
498
|
+
},
|
|
499
|
+
2: {
|
|
500
|
+
id: 2,
|
|
501
|
+
name: 'English Assignments',
|
|
502
|
+
collections: [4],
|
|
503
|
+
items: []
|
|
504
|
+
},
|
|
505
|
+
3: {
|
|
506
|
+
id: 3,
|
|
507
|
+
name: 'Math Assignments',
|
|
508
|
+
collections: [5],
|
|
509
|
+
items: [2, 1]
|
|
510
|
+
},
|
|
511
|
+
4: {
|
|
512
|
+
id: 4,
|
|
513
|
+
name: 'Reading Assignments',
|
|
514
|
+
collections: [],
|
|
515
|
+
items: [4]
|
|
516
|
+
},
|
|
517
|
+
5: { id: 5, name: 'Advanced Math Assignments', items: [5] }
|
|
518
|
+
}}
|
|
519
|
+
items={{
|
|
520
|
+
1: { id: 1, name: 'Addition Worksheet' },
|
|
521
|
+
2: { id: 2, name: 'Subtraction Worksheet' },
|
|
522
|
+
3: { id: 3, name: 'General Questions' },
|
|
523
|
+
4: { id: 4, name: 'Vogon Poetry' },
|
|
524
|
+
5: {
|
|
525
|
+
id: 5,
|
|
526
|
+
name: 'Bistromath',
|
|
527
|
+
descriptor: 'Explain the Bistromathic Drive'
|
|
528
|
+
}
|
|
529
|
+
}}
|
|
530
|
+
defaultExpanded={[1, 3]}
|
|
531
|
+
rootId={1}
|
|
532
|
+
sortOrder={sorted ? (a, b) => a.name.localeCompare(b.name) : () => 0}
|
|
533
|
+
/>
|
|
534
|
+
</>
|
|
535
|
+
)
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
render(<Example />)
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
There is another way to sort the children of one collection. By adding the `compareFunc` as the comparison function to the collection's properties. This will be effective only within the collection's scope. For more convenience, we support a prop called `type` to specify whether the collection's children is either an item or a subcollection (this is only make sense in `compareFunc`)
|
|
542
|
+
|
|
543
|
+
```js
|
|
544
|
+
---
|
|
545
|
+
type: example
|
|
546
|
+
---
|
|
547
|
+
const Example = () => {
|
|
548
|
+
const [size, setSize] = useState('medium')
|
|
549
|
+
|
|
550
|
+
return (
|
|
551
|
+
<TreeBrowser
|
|
552
|
+
size={size}
|
|
553
|
+
collections={{
|
|
554
|
+
1: {
|
|
555
|
+
id: 1,
|
|
556
|
+
name: 'Assignments',
|
|
557
|
+
collections: [3, 2],
|
|
558
|
+
items: [3],
|
|
559
|
+
descriptor: 'Class Assignments',
|
|
560
|
+
// Sort the direct children of "Assignment" by their name in alphabetical order
|
|
561
|
+
compareFunc: (a, b) => a.name.localeCompare(b.name)
|
|
562
|
+
},
|
|
563
|
+
2: {
|
|
564
|
+
id: 2,
|
|
565
|
+
name: 'English Assignments',
|
|
566
|
+
collections: [4],
|
|
567
|
+
items: []
|
|
568
|
+
},
|
|
569
|
+
3: {
|
|
570
|
+
id: 3,
|
|
571
|
+
name: 'Math Assignments',
|
|
572
|
+
collections: [5],
|
|
573
|
+
items: [2, 1],
|
|
574
|
+
// The items appear before subcollections
|
|
575
|
+
compareFunc: (a, b) => {
|
|
576
|
+
if (a.type === 'item' && b.type === 'collection') {
|
|
577
|
+
return -1
|
|
578
|
+
}
|
|
579
|
+
if (a.type === 'collection' && b.type === 'item') {
|
|
580
|
+
return 1
|
|
581
|
+
}
|
|
582
|
+
return 0
|
|
583
|
+
}
|
|
584
|
+
},
|
|
585
|
+
4: {
|
|
586
|
+
id: 4,
|
|
587
|
+
name: 'Reading Assignments',
|
|
588
|
+
collections: [],
|
|
589
|
+
items: [4]
|
|
590
|
+
},
|
|
591
|
+
5: { id: 5, name: 'Advanced Math Assignments', items: [5] }
|
|
592
|
+
}}
|
|
593
|
+
items={{
|
|
594
|
+
1: { id: 1, name: 'Addition Worksheet' },
|
|
595
|
+
2: { id: 2, name: 'Subtraction Worksheet' },
|
|
596
|
+
3: { id: 3, name: 'General Questions' },
|
|
597
|
+
4: { id: 4, name: 'Vogon Poetry' },
|
|
598
|
+
5: {
|
|
599
|
+
id: 5,
|
|
600
|
+
name: 'Bistromath',
|
|
601
|
+
descriptor: 'Explain the Bistromathic Drive'
|
|
602
|
+
}
|
|
603
|
+
}}
|
|
604
|
+
defaultExpanded={[1, 3]}
|
|
605
|
+
rootId={1}
|
|
606
|
+
/>
|
|
607
|
+
)
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
render(<Example />)
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
### showRootCollection
|
|
614
|
+
|
|
615
|
+
The `showRootCollection` prop sets whether the root collection (specified in `rootId` prop) is displayed or to begin with its immediate sub-collections and items instead. It defaults to `true`.
|
|
616
|
+
|
|
617
|
+
```js
|
|
618
|
+
---
|
|
619
|
+
type: example
|
|
620
|
+
---
|
|
621
|
+
const Example = () => {
|
|
622
|
+
const [showRootCollection, setShowRootCollection] = useState(true)
|
|
623
|
+
|
|
624
|
+
const handleSwitch = () => {
|
|
625
|
+
setShowRootCollection(!showRootCollection)
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
const renderNode = () => {
|
|
629
|
+
return (
|
|
630
|
+
<TreeBrowser.Node itemIcon={<PlusInstUIIcon />}>More</TreeBrowser.Node>
|
|
631
|
+
)
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
return (
|
|
635
|
+
<>
|
|
636
|
+
<View display="block" margin="none none medium">
|
|
637
|
+
<Checkbox
|
|
638
|
+
label="showRootCollection"
|
|
639
|
+
variant="toggle"
|
|
640
|
+
size="medium"
|
|
641
|
+
checked={showRootCollection}
|
|
642
|
+
onChange={handleSwitch}
|
|
643
|
+
/>
|
|
644
|
+
</View>
|
|
645
|
+
|
|
646
|
+
<TreeBrowser
|
|
647
|
+
collections={{
|
|
648
|
+
1: {
|
|
649
|
+
id: 1,
|
|
650
|
+
name: 'Assignments',
|
|
651
|
+
collections: [2, 3],
|
|
652
|
+
items: [3, 5],
|
|
653
|
+
descriptor: 'Class Assignments',
|
|
654
|
+
renderAfterItems: renderNode()
|
|
655
|
+
},
|
|
656
|
+
2: {
|
|
657
|
+
id: 2,
|
|
658
|
+
name: 'English Assignments',
|
|
659
|
+
collections: [4],
|
|
660
|
+
items: []
|
|
661
|
+
},
|
|
662
|
+
3: {
|
|
663
|
+
id: 3,
|
|
664
|
+
name: 'Math Assignments',
|
|
665
|
+
collections: [5],
|
|
666
|
+
items: [1, 2]
|
|
667
|
+
},
|
|
668
|
+
4: {
|
|
669
|
+
id: 4,
|
|
670
|
+
name: 'Reading Assignments',
|
|
671
|
+
collections: [],
|
|
672
|
+
items: [4]
|
|
673
|
+
},
|
|
674
|
+
5: { id: 5, name: 'Advanced Math Assignments', items: [5] }
|
|
675
|
+
}}
|
|
676
|
+
items={{
|
|
677
|
+
1: { id: 1, name: 'Addition Worksheet' },
|
|
678
|
+
2: { id: 2, name: 'Subtraction Worksheet' },
|
|
679
|
+
3: { id: 3, name: 'General Questions' },
|
|
680
|
+
4: { id: 4, name: 'Vogon Poetry' },
|
|
681
|
+
5: {
|
|
682
|
+
id: 5,
|
|
683
|
+
name: 'Bistromath',
|
|
684
|
+
descriptor: 'Explain the Bistromathic Drive'
|
|
685
|
+
}
|
|
686
|
+
}}
|
|
687
|
+
defaultExpanded={[1, 3]}
|
|
688
|
+
rootId={1}
|
|
689
|
+
showRootCollection={showRootCollection}
|
|
690
|
+
/>
|
|
691
|
+
</>
|
|
692
|
+
)
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
render(<Example />)
|
|
696
|
+
```
|
|
697
|
+
|
|
698
|
+
### Guidelines
|
|
699
|
+
|
|
700
|
+
```js
|
|
701
|
+
---
|
|
702
|
+
type: embed
|
|
703
|
+
---
|
|
704
|
+
<Guidelines>
|
|
705
|
+
<Figure recommendation="yes" title="Do">
|
|
706
|
+
<Figure.Item>Use for browsing hierarchical content</Figure.Item>
|
|
707
|
+
</Figure>
|
|
708
|
+
<Figure recommendation="no" title="Don't">
|
|
709
|
+
<Figure.Item>Use for site navigation</Figure.Item>
|
|
710
|
+
</Figure>
|
|
711
|
+
</Guidelines>
|
|
712
|
+
```
|