@instructure/ui-tree-browser 10.3.0 → 10.3.1-snapshot-0

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.
@@ -7,60 +7,163 @@ to receive a normalized data structure, examples can be seen at https://github.c
7
7
 
8
8
  ### Size
9
9
 
10
- ```js
11
- ---
12
- type: example
13
- ---
14
- class Example extends React.Component {
15
- constructor (props) {
16
- super(props)
17
- this.state = {
18
- size: 'medium'
10
+ - ```js
11
+ class Example extends React.Component {
12
+ constructor(props) {
13
+ super(props)
14
+ this.state = {
15
+ size: 'medium'
16
+ }
17
+
18
+ this.sizes = ['small', 'medium', 'large']
19
+ }
20
+
21
+ handleSizeSelect = (e, size) => {
22
+ this.setState({ size })
19
23
  }
20
24
 
21
- this.sizes = ['small', 'medium', 'large']
25
+ render() {
26
+ return (
27
+ <>
28
+ <View display="block" margin="none none medium">
29
+ <RadioInputGroup
30
+ name="treeBrowserSize"
31
+ defaultValue="medium"
32
+ description={
33
+ <ScreenReaderContent>
34
+ TreeBrowser size selector
35
+ </ScreenReaderContent>
36
+ }
37
+ variant="toggle"
38
+ onChange={this.handleSizeSelect}
39
+ >
40
+ {this.sizes.map((size) => (
41
+ <RadioInput key={size} label={size} value={size} />
42
+ ))}
43
+ </RadioInputGroup>
44
+ </View>
45
+
46
+ <TreeBrowser
47
+ size={this.state.size}
48
+ collections={{
49
+ 1: {
50
+ id: 1,
51
+ name: 'Assignments',
52
+ collections: [2, 3],
53
+ items: [3],
54
+ descriptor: 'Class Assignments'
55
+ },
56
+ 2: {
57
+ id: 2,
58
+ name: 'English Assignments',
59
+ collections: [4],
60
+ items: []
61
+ },
62
+ 3: {
63
+ id: 3,
64
+ name: 'Math Assignments',
65
+ collections: [5],
66
+ items: [1, 2]
67
+ },
68
+ 4: {
69
+ id: 4,
70
+ name: 'Reading Assignments',
71
+ collections: [],
72
+ items: [4]
73
+ },
74
+ 5: { id: 5, name: 'Advanced Math Assignments', items: [5] }
75
+ }}
76
+ items={{
77
+ 1: { id: 1, name: 'Addition Worksheet' },
78
+ 2: { id: 2, name: 'Subtraction Worksheet' },
79
+ 3: { id: 3, name: 'General Questions' },
80
+ 4: { id: 4, name: 'Vogon Poetry' },
81
+ 5: {
82
+ id: 5,
83
+ name: 'Bistromath',
84
+ descriptor: 'Explain the Bistromathic Drive'
85
+ }
86
+ }}
87
+ defaultExpanded={[1, 3]}
88
+ rootId={1}
89
+ />
90
+ </>
91
+ )
92
+ }
22
93
  }
23
94
 
24
- handleSizeSelect = (e, size) => {
25
- this.setState({ size })
26
- };
95
+ render(<Example />)
96
+ ```
97
+
98
+ - ```js
99
+ const Example = () => {
100
+ const [size, setSize] = useState('medium')
101
+ const sizes = ['small', 'medium', 'large']
102
+
103
+ const handleSizeSelect = (e, size) => {
104
+ setSize(size)
105
+ }
27
106
 
28
- render () {
29
107
  return (
30
108
  <>
31
109
  <View display="block" margin="none none medium">
32
110
  <RadioInputGroup
33
111
  name="treeBrowserSize"
34
112
  defaultValue="medium"
35
- description={<ScreenReaderContent>TreeBrowser size selector</ScreenReaderContent>}
113
+ description={
114
+ <ScreenReaderContent>
115
+ TreeBrowser size selector
116
+ </ScreenReaderContent>
117
+ }
36
118
  variant="toggle"
37
- onChange={this.handleSizeSelect}
119
+ onChange={handleSizeSelect}
38
120
  >
39
- {this.sizes.map((size) => <RadioInput key={size} label={size} value={size} />)}
121
+ {sizes.map((size) => (
122
+ <RadioInput key={size} label={size} value={size} />
123
+ ))}
40
124
  </RadioInputGroup>
41
125
  </View>
42
126
 
43
127
  <TreeBrowser
44
- size={this.state.size}
128
+ size={size}
45
129
  collections={{
46
130
  1: {
47
131
  id: 1,
48
- name: "Assignments",
49
- collections: [2,3],
132
+ name: 'Assignments',
133
+ collections: [2, 3],
50
134
  items: [3],
51
- descriptor: "Class Assignments"
135
+ descriptor: 'Class Assignments'
136
+ },
137
+ 2: {
138
+ id: 2,
139
+ name: 'English Assignments',
140
+ collections: [4],
141
+ items: []
142
+ },
143
+ 3: {
144
+ id: 3,
145
+ name: 'Math Assignments',
146
+ collections: [5],
147
+ items: [1, 2]
148
+ },
149
+ 4: {
150
+ id: 4,
151
+ name: 'Reading Assignments',
152
+ collections: [],
153
+ items: [4]
52
154
  },
53
- 2: { id: 2, name: "English Assignments", collections: [4], items: [] },
54
- 3: { id: 3, name: "Math Assignments", collections: [5], items: [1,2] },
55
- 4: { id: 4, name: "Reading Assignments", collections: [], items: [4] },
56
- 5: { id: 5, name: "Advanced Math Assignments", items: [5]}
155
+ 5: { id: 5, name: 'Advanced Math Assignments', items: [5] }
57
156
  }}
58
157
  items={{
59
- 1: { id: 1, name: "Addition Worksheet" },
60
- 2: { id: 2, name: "Subtraction Worksheet" },
61
- 3: { id: 3, name: "General Questions" },
62
- 4: { id: 4, name: "Vogon Poetry" },
63
- 5: { id: 5, name: "Bistromath", descriptor: "Explain the Bistromathic Drive" }
158
+ 1: { id: 1, name: 'Addition Worksheet' },
159
+ 2: { id: 2, name: 'Subtraction Worksheet' },
160
+ 3: { id: 3, name: 'General Questions' },
161
+ 4: { id: 4, name: 'Vogon Poetry' },
162
+ 5: {
163
+ id: 5,
164
+ name: 'Bistromath',
165
+ descriptor: 'Explain the Bistromathic Drive'
166
+ }
64
167
  }}
65
168
  defaultExpanded={[1, 3]}
66
169
  rootId={1}
@@ -68,80 +171,184 @@ class Example extends React.Component {
68
171
  </>
69
172
  )
70
173
  }
71
- }
72
174
 
73
- render(<Example/>)
74
-
75
- ```
175
+ render(<Example />)
176
+ ```
76
177
 
77
178
  ### Managing State
78
179
 
79
180
  `<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.
80
181
 
81
- ```js
82
- ---
83
- type: example
84
- ---
85
- class Example extends React.Component {
86
- constructor (props) {
87
- super(props)
88
- this.state = {
89
- expanded: [2]
182
+ - ```js
183
+ class Example extends React.Component {
184
+ constructor(props) {
185
+ super(props)
186
+ this.state = {
187
+ expanded: [2]
188
+ }
189
+ }
190
+
191
+ handleCollectionClick = (id, collection) => {
192
+ console.log(collection.id)
193
+ }
194
+
195
+ handleCollectionToggle = (collection) => {
196
+ this.setState((state) => {
197
+ const expanded = [...state.expanded]
198
+ const index = expanded.indexOf(collection.id)
199
+
200
+ if (!collection.expanded) {
201
+ expanded.splice(index, 1)
202
+ } else if (index < 0) {
203
+ expanded.push(collection.id)
204
+ }
205
+
206
+ return { expanded }
207
+ })
208
+ }
209
+
210
+ render() {
211
+ return (
212
+ <TreeBrowser
213
+ variant="indent"
214
+ selectionType="single"
215
+ collections={{
216
+ 1: { id: 1, name: 'Grade 1', collections: [2, 3, 6] },
217
+ 2: {
218
+ id: 2,
219
+ name: 'Math Outcomes',
220
+ collections: [4],
221
+ items: [3, 4],
222
+ descriptor: '1 Group | 2 Outcomes'
223
+ },
224
+ 3: {
225
+ id: 3,
226
+ name: 'Reading Outcome',
227
+ collections: [5],
228
+ items: [1, 2],
229
+ descriptor: '1 Group | 2 Outcomes'
230
+ },
231
+ 4: {
232
+ id: 4,
233
+ name: 'Advanced Math',
234
+ items: [6],
235
+ descriptor: '1 Outcome'
236
+ },
237
+ 5: {
238
+ id: 5,
239
+ name: 'Advanced Reading',
240
+ items: [5],
241
+ descriptor: '1 Group | 2 Outcomes'
242
+ },
243
+ 6: {
244
+ id: 6,
245
+ name: 'Advanced Outcomes',
246
+ items: [5, 6],
247
+ descriptor: '2 Outcomes'
248
+ }
249
+ }}
250
+ items={{
251
+ 1: { id: 1, name: 'Can read' },
252
+ 2: { id: 2, name: 'Can write' },
253
+ 3: { id: 3, name: 'Can add' },
254
+ 4: { id: 4, name: 'Can subtract' },
255
+ 5: { id: 5, name: 'Can read Shakespeare' },
256
+ 6: { id: 6, name: 'Can do quantum physics' }
257
+ }}
258
+ showRootCollection={false}
259
+ rootId={1}
260
+ expanded={this.state.expanded}
261
+ onCollectionToggle={this.handleCollectionToggle}
262
+ onCollectionClick={this.handleCollectionClick}
263
+ />
264
+ )
90
265
  }
91
266
  }
92
267
 
93
- handleCollectionClick = (id, collection) => {
94
- console.log(collection.id)
95
- };
268
+ render(<Example />)
269
+ ```
96
270
 
97
- handleCollectionToggle = (collection) => {
98
- this.setState((state) => {
99
- const expanded = [...state.expanded]
100
- const index = expanded.indexOf(collection.id)
271
+ - ```js
272
+ const Example = () => {
273
+ const [expanded, setExpanded] = useState([2])
101
274
 
102
- if (!collection.expanded) {
103
- expanded.splice(index, 1)
104
- } else if (index < 0) {
105
- expanded.push(collection.id)
106
- }
275
+ const handleCollectionClick = (id, collection) => {
276
+ console.log(collection.id)
277
+ }
278
+
279
+ const handleCollectionToggle = (collection) => {
280
+ setExpanded((prevExpanded) => {
281
+ const newExpanded = [...prevExpanded]
282
+ const index = newExpanded.indexOf(collection.id)
107
283
 
108
- return { expanded }
109
- })
110
- };
284
+ if (!collection.expanded) {
285
+ newExpanded.splice(index, 1)
286
+ } else if (index < 0) {
287
+ newExpanded.push(collection.id)
288
+ }
289
+
290
+ return newExpanded
291
+ })
292
+ }
111
293
 
112
- render () {
113
294
  return (
114
295
  <TreeBrowser
115
296
  variant="indent"
116
297
  selectionType="single"
117
298
  collections={{
118
- 1: { id: 1, name: "Grade 1", collections: [2,3,6] },
119
- 2: { id: 2, name: "Math Outcomes", collections: [4], items: [3,4], descriptor: "1 Group | 2 Outcomes" },
120
- 3: { id: 3, name: "Reading Outcome", collections: [5], items: [1,2], descriptor: "1 Group | 2 Outcomes" },
121
- 4: { id: 4, name: "Advanced Math", items: [6], descriptor: "1 Outcome" },
122
- 5: { id: 5, name: "Advanced Reading", items: [5], descriptor: "1 Group | 2 Outcomes" },
123
- 6: { id: 6, name: "Advanced Outcomes", items: [5,6], descriptor: "2 Outcomes" },
299
+ 1: { id: 1, name: 'Grade 1', collections: [2, 3, 6] },
300
+ 2: {
301
+ id: 2,
302
+ name: 'Math Outcomes',
303
+ collections: [4],
304
+ items: [3, 4],
305
+ descriptor: '1 Group | 2 Outcomes'
306
+ },
307
+ 3: {
308
+ id: 3,
309
+ name: 'Reading Outcome',
310
+ collections: [5],
311
+ items: [1, 2],
312
+ descriptor: '1 Group | 2 Outcomes'
313
+ },
314
+ 4: {
315
+ id: 4,
316
+ name: 'Advanced Math',
317
+ items: [6],
318
+ descriptor: '1 Outcome'
319
+ },
320
+ 5: {
321
+ id: 5,
322
+ name: 'Advanced Reading',
323
+ items: [5],
324
+ descriptor: '1 Group | 2 Outcomes'
325
+ },
326
+ 6: {
327
+ id: 6,
328
+ name: 'Advanced Outcomes',
329
+ items: [5, 6],
330
+ descriptor: '2 Outcomes'
331
+ }
124
332
  }}
125
333
  items={{
126
- 1: { id: 1, name: "Can read" },
127
- 2: { id: 2, name: "Can write" },
128
- 3: { id: 3, name: "Can add" },
129
- 4: { id: 4, name: "Can subtract" },
130
- 5: { id: 5, name: "Can read Shakespeare" },
131
- 6: { id: 6, name: "Can do quantum physics" }
334
+ 1: { id: 1, name: 'Can read' },
335
+ 2: { id: 2, name: 'Can write' },
336
+ 3: { id: 3, name: 'Can add' },
337
+ 4: { id: 4, name: 'Can subtract' },
338
+ 5: { id: 5, name: 'Can read Shakespeare' },
339
+ 6: { id: 6, name: 'Can do quantum physics' }
132
340
  }}
133
341
  showRootCollection={false}
134
342
  rootId={1}
135
- expanded={this.state.expanded}
136
- onCollectionToggle={this.handleCollectionToggle}
137
- onCollectionClick={this.handleCollectionClick}
343
+ expanded={expanded}
344
+ onCollectionToggle={handleCollectionToggle}
345
+ onCollectionClick={handleCollectionClick}
138
346
  />
139
347
  )
140
348
  }
141
- }
142
349
 
143
- render(<Example/>)
144
- ```
350
+ render(<Example />)
351
+ ```
145
352
 
146
353
  ### Customizing Icons
147
354
 
@@ -292,117 +499,240 @@ type: example
292
499
 
293
500
  An example of a `<TreeBrowser />` with a custom item after each collection.
294
501
 
295
- ```js
296
- ---
297
- type: example
298
- ---
299
- class Example extends React.Component {
300
- constructor(props) {
301
- super(props)
302
- this.state = {
303
- expanded: true,
304
- hoveredLine: null
502
+ - ```js
503
+ class Example extends React.Component {
504
+ constructor(props) {
505
+ super(props)
506
+ this.state = {
507
+ expanded: true,
508
+ hoveredLine: null
509
+ }
305
510
  }
306
- }
307
511
 
308
- renderInput = () => {
309
- const { expanded } = this.state
310
- if (expanded) {
311
- return (
312
- <InstUISettingsProvider
313
- theme={
314
- this.state.hoveredLine === 'renderAfter'
315
- ? {
316
- componentOverrides: {
317
- View: {
318
- focusColorInfo: 'white'
319
- },
320
- TextInput: {
321
- focusOutlineColor: 'white'
512
+ renderInput = () => {
513
+ const { expanded } = this.state
514
+ if (expanded) {
515
+ return (
516
+ <InstUISettingsProvider
517
+ theme={
518
+ this.state.hoveredLine === 'renderAfter'
519
+ ? {
520
+ componentOverrides: {
521
+ View: {
522
+ focusColorInfo: 'white'
523
+ },
524
+ TextInput: {
525
+ focusOutlineColor: 'white'
526
+ }
322
527
  }
323
528
  }
324
- }
325
- : undefined
326
- }
327
- >
328
- <View
329
- as="div"
330
- padding="xx-small"
331
- onFocus={(e) => e.stopPropagation()}
332
- onClick={(e) => e.stopPropagation()}
333
- onMouseEnter={() => this.setState({ hoveredLine: 'renderAfter' })}
334
- onMouseLeave={() => this.setState({ hoveredLine: 'null' })}
529
+ : undefined
530
+ }
335
531
  >
336
- <TextInput
337
- placeholder="Enter new group name"
338
- display="inline-block"
339
- width="12rem"
340
- renderLabel=""
341
- onKeyDown={(e) => {
342
- e.stopPropagation()
343
- }}
344
- />
345
- <IconButton
346
- screenReaderLabel="Cancel"
347
- onClick={(e) => this.setExpand(e, !expanded)}
348
- onKeyDown={(e) => {
349
- if (e.code === 'Space' || e.code === 'Enter') {
350
- e.preventDefault()
351
- this.setExpand(e, !expanded)
352
- }
353
- }}
354
- margin="0 0 0 small"
355
- >
356
- <IconXSolid />
357
- </IconButton>
358
- <IconButton
359
- screenReaderLabel="Add new group"
360
- onClick={(e) => this.setExpand(e, !expanded)}
361
- onKeyDown={(e) => {
362
- if (e.code === 'Space' || e.code === 'Enter') {
363
- e.preventDefault()
364
- this.setExpand(e, !expanded)
365
- }
366
- }}
367
- margin="0 0 0 small"
532
+ <View
533
+ as="div"
534
+ padding="xx-small"
535
+ onFocus={(e) => e.stopPropagation()}
536
+ onClick={(e) => e.stopPropagation()}
537
+ onMouseEnter={() => this.setState({ hoveredLine: 'renderAfter' })}
538
+ onMouseLeave={() => this.setState({ hoveredLine: 'null' })}
368
539
  >
369
- <IconCheckSolid />
370
- </IconButton>
371
- </View>
372
- </InstUISettingsProvider>
540
+ <TextInput
541
+ placeholder="Enter new group name"
542
+ display="inline-block"
543
+ width="12rem"
544
+ renderLabel=""
545
+ onKeyDown={(e) => {
546
+ e.stopPropagation()
547
+ }}
548
+ />
549
+ <IconButton
550
+ screenReaderLabel="Cancel"
551
+ onClick={(e) => this.setExpand(e, !expanded)}
552
+ onKeyDown={(e) => {
553
+ if (e.code === 'Space' || e.code === 'Enter') {
554
+ e.preventDefault()
555
+ this.setExpand(e, !expanded)
556
+ }
557
+ }}
558
+ margin="0 0 0 small"
559
+ >
560
+ <IconXSolid />
561
+ </IconButton>
562
+ <IconButton
563
+ screenReaderLabel="Add new group"
564
+ onClick={(e) => this.setExpand(e, !expanded)}
565
+ onKeyDown={(e) => {
566
+ if (e.code === 'Space' || e.code === 'Enter') {
567
+ e.preventDefault()
568
+ this.setExpand(e, !expanded)
569
+ }
570
+ }}
571
+ margin="0 0 0 small"
572
+ >
573
+ <IconCheckSolid />
574
+ </IconButton>
575
+ </View>
576
+ </InstUISettingsProvider>
577
+ )
578
+ }
579
+
580
+ return <View as="div">Create New Group</View>
581
+ }
582
+
583
+ setExpand = (e, expanded) => {
584
+ e.stopPropagation()
585
+ this.setState({ expanded })
586
+ this._node.focus()
587
+ }
588
+
589
+ renderNode = () => {
590
+ const { expanded } = this.state
591
+ return (
592
+ <TreeBrowser.Node
593
+ containerRef={(el) => (this._node = el)}
594
+ onClick={(e) => this.setExpand(e, !expanded)}
595
+ onKeyDown={(e) => {
596
+ if (e.code === 'Space' || e.code === 'Enter') {
597
+ e.preventDefault()
598
+ this.setExpand(e, !expanded)
599
+ }
600
+ }}
601
+ itemIcon={this.state.expanded ? '' : <IconPlusLine />}
602
+ size="large"
603
+ >
604
+ {this.renderInput()}
605
+ </TreeBrowser.Node>
373
606
  )
374
607
  }
375
608
 
376
- return <View as="div">Create New Group</View>
609
+ render() {
610
+ return (
611
+ <TreeBrowser
612
+ selectionType="single"
613
+ size="large"
614
+ defaultExpanded={[1, 2]}
615
+ collections={{
616
+ 1: {
617
+ id: 1,
618
+ name: 'Grade 1',
619
+ collections: [2]
620
+ },
621
+ 2: {
622
+ id: 2,
623
+ name: 'Math Outcomes',
624
+ collections: [],
625
+ items: [1, 2],
626
+ descriptor: '1 Group | 2 Outcomes',
627
+ renderAfterItems: this.renderNode()
628
+ }
629
+ }}
630
+ items={{
631
+ 1: { id: 1, name: 'Can add' },
632
+ 2: { id: 2, name: 'Can subtract' }
633
+ }}
634
+ showRootCollection={true}
635
+ rootId={1}
636
+ />
637
+ )
638
+ }
377
639
  }
378
640
 
379
- setExpand = (e, expanded) => {
380
- e.stopPropagation()
381
- this.setState({ expanded })
382
- this._node.focus()
383
- }
641
+ render(<Example />)
642
+ ```
643
+
644
+ - ```js
645
+ const Example = () => {
646
+ const [expanded, setExpanded] = useState(true)
647
+ const [hoveredLine, setHoveredLine] = useState(null)
648
+ const nodeRef = useRef(null)
649
+
650
+ const handleExpandToggle = useCallback((e, newExpandedState) => {
651
+ e.stopPropagation()
652
+ setExpanded(newExpandedState)
653
+ nodeRef.current?.focus()
654
+ }, [])
655
+
656
+ const handleKeyPress = useCallback(
657
+ (e, newExpandedState) => {
658
+ if (e.code === 'Space' || e.code === 'Enter') {
659
+ e.preventDefault()
660
+ handleExpandToggle(e, newExpandedState)
661
+ }
662
+ },
663
+ [handleExpandToggle]
664
+ )
384
665
 
385
- renderNode = () => {
386
- const { expanded } = this.state
387
- return (
666
+ const renderInput = () => {
667
+ if (expanded) {
668
+ return (
669
+ <InstUISettingsProvider
670
+ theme={
671
+ hoveredLine === 'renderAfter'
672
+ ? {
673
+ componentOverrides: {
674
+ View: {
675
+ focusColorInfo: 'white'
676
+ },
677
+ TextInput: {
678
+ focusOutlineColor: 'white'
679
+ }
680
+ }
681
+ }
682
+ : undefined
683
+ }
684
+ >
685
+ <View
686
+ as="div"
687
+ padding="xx-small"
688
+ onFocus={(e) => e.stopPropagation()}
689
+ onClick={(e) => e.stopPropagation()}
690
+ onMouseEnter={() => setHoveredLine('renderAfter')}
691
+ onMouseLeave={() => setHoveredLine(null)}
692
+ >
693
+ <TextInput
694
+ placeholder="Enter new group name"
695
+ display="inline-block"
696
+ width="12rem"
697
+ renderLabel=""
698
+ onKeyDown={(e) => e.stopPropagation()}
699
+ />
700
+ <IconButton
701
+ screenReaderLabel="Cancel"
702
+ onClick={(e) => handleExpandToggle(e, false)}
703
+ onKeyDown={(e) => handleKeyPress(e, false)}
704
+ margin="0 0 0 small"
705
+ >
706
+ <IconXSolid />
707
+ </IconButton>
708
+ <IconButton
709
+ screenReaderLabel="Add new group"
710
+ onClick={(e) => handleExpandToggle(e, false)}
711
+ onKeyDown={(e) => handleKeyPress(e, false)}
712
+ margin="0 0 0 small"
713
+ >
714
+ <IconCheckSolid />
715
+ </IconButton>
716
+ </View>
717
+ </InstUISettingsProvider>
718
+ )
719
+ }
720
+
721
+ return <View as="div">Create New Group</View>
722
+ }
723
+
724
+ const renderNode = () => (
388
725
  <TreeBrowser.Node
389
- containerRef={(el) => (this._node = el)}
390
- onClick={(e) => this.setExpand(e, !expanded)}
391
- onKeyDown={(e) => {
392
- if (e.code === 'Space' || e.code === 'Enter') {
393
- e.preventDefault()
394
- this.setExpand(e, !expanded)
395
- }
396
- }}
397
- itemIcon={this.state.expanded ? '' : <IconPlusLine />}
726
+ containerRef={(el) => (nodeRef.current = el)}
727
+ onClick={(e) => handleExpandToggle(e, !expanded)}
728
+ onKeyDown={(e) => handleKeyPress(e, !expanded)}
729
+ itemIcon={expanded ? '' : <IconPlusLine />}
398
730
  size="large"
399
731
  >
400
- {this.renderInput()}
732
+ {renderInput()}
401
733
  </TreeBrowser.Node>
402
734
  )
403
- }
404
735
 
405
- render() {
406
736
  return (
407
737
  <TreeBrowser
408
738
  selectionType="single"
@@ -420,7 +750,7 @@ class Example extends React.Component {
420
750
  collections: [],
421
751
  items: [1, 2],
422
752
  descriptor: '1 Group | 2 Outcomes',
423
- renderAfterItems: this.renderNode()
753
+ renderAfterItems: renderNode()
424
754
  }
425
755
  }}
426
756
  items={{
@@ -432,10 +762,9 @@ class Example extends React.Component {
432
762
  />
433
763
  )
434
764
  }
435
- }
436
765
 
437
- render(<Example/>)
438
- ```
766
+ render(<Example />)
767
+ ```
439
768
 
440
769
  ### Change the order of appearance of items and collections
441
770
 
@@ -449,156 +778,408 @@ This works with all collections and items of the TreeBrowser.
449
778
 
450
779
  ---
451
780
 
452
- ```js
453
- ---
454
- type: example
455
- ---
456
- class Example extends React.Component {
457
- constructor (props) {
458
- super(props)
459
- this.state = {
460
- size: 'medium',
461
- sorted: false
781
+ - ```js
782
+ class Example extends React.Component {
783
+ constructor(props) {
784
+ super(props)
785
+ this.state = {
786
+ size: 'medium',
787
+ sorted: false
788
+ }
462
789
  }
463
- }
464
- toggleSort = (event)=>{ this.setState({sorted:!this.state.sorted}) }
465
- render () {
466
- return (
467
- <>
468
- <View display="block" margin="none none medium">
469
- <FormFieldGroup description="Turn of/off sorting">
790
+ toggleSort = (event) => {
791
+ this.setState({ sorted: !this.state.sorted })
792
+ }
793
+ render() {
794
+ return (
795
+ <>
796
+ <View display="block" margin="none none medium">
797
+ <FormFieldGroup description="Turn on/off sorting">
470
798
  <Checkbox
471
799
  checked={this.state.sorted}
472
800
  label="Sort"
473
801
  onChange={this.toggleSort}
474
802
  />
475
- </FormFieldGroup>
803
+ </FormFieldGroup>
804
+ </View>
805
+
806
+ <TreeBrowser
807
+ size={this.state.size}
808
+ collections={{
809
+ 1: {
810
+ id: 1,
811
+ name: 'Assignments',
812
+ collections: [3, 2],
813
+ items: [3],
814
+ descriptor: 'Class Assignments'
815
+ },
816
+ 2: {
817
+ id: 2,
818
+ name: 'English Assignments',
819
+ collections: [4],
820
+ items: []
821
+ },
822
+ 3: {
823
+ id: 3,
824
+ name: 'Math Assignments',
825
+ collections: [5],
826
+ items: [2, 1]
827
+ },
828
+ 4: {
829
+ id: 4,
830
+ name: 'Reading Assignments',
831
+ collections: [],
832
+ items: [4]
833
+ },
834
+ 5: { id: 5, name: 'Advanced Math Assignments', items: [5] }
835
+ }}
836
+ items={{
837
+ 1: { id: 1, name: 'Addition Worksheet' },
838
+ 2: { id: 2, name: 'Subtraction Worksheet' },
839
+ 3: { id: 3, name: 'General Questions' },
840
+ 4: { id: 4, name: 'Vogon Poetry' },
841
+ 5: {
842
+ id: 5,
843
+ name: 'Bistromath',
844
+ descriptor: 'Explain the Bistromathic Drive'
845
+ }
846
+ }}
847
+ defaultExpanded={[1, 3]}
848
+ rootId={1}
849
+ sortOrder={
850
+ this.state.sorted
851
+ ? (a, b) => {
852
+ return a.name.localeCompare(b.name)
853
+ }
854
+ : (a, b) => {
855
+ return 0
856
+ }
857
+ }
858
+ />
859
+ </>
860
+ )
861
+ }
862
+ }
863
+
864
+ render(<Example />)
865
+ ```
866
+
867
+ - ```js
868
+ const Example = () => {
869
+ const [size, setSize] = useState('medium')
870
+ const [sorted, setSorted] = useState(false)
871
+
872
+ const toggleSort = () => {
873
+ setSorted(!sorted)
874
+ }
875
+
876
+ return (
877
+ <>
878
+ <View display="block" margin="none none medium">
879
+ <FormFieldGroup description="Turn on/off sorting">
880
+ <Checkbox checked={sorted} label="Sort" onChange={toggleSort} />
881
+ </FormFieldGroup>
476
882
  </View>
477
883
 
478
884
  <TreeBrowser
479
- size={this.state.size}
885
+ size={size}
480
886
  collections={{
481
887
  1: {
482
888
  id: 1,
483
- name: "Assignments",
484
- collections: [3,2],
889
+ name: 'Assignments',
890
+ collections: [3, 2],
485
891
  items: [3],
486
- descriptor: "Class Assignments"
892
+ descriptor: 'Class Assignments'
893
+ },
894
+ 2: {
895
+ id: 2,
896
+ name: 'English Assignments',
897
+ collections: [4],
898
+ items: []
487
899
  },
488
- 2: { id: 2, name: "English Assignments", collections: [4], items: [] },
489
- 3: { id: 3, name: "Math Assignments", collections: [5], items: [2,1] },
490
- 4: { id: 4, name: "Reading Assignments", collections: [], items: [4] },
491
- 5: { id: 5, name: "Advanced Math Assignments", items: [5]}
900
+ 3: {
901
+ id: 3,
902
+ name: 'Math Assignments',
903
+ collections: [5],
904
+ items: [2, 1]
905
+ },
906
+ 4: {
907
+ id: 4,
908
+ name: 'Reading Assignments',
909
+ collections: [],
910
+ items: [4]
911
+ },
912
+ 5: { id: 5, name: 'Advanced Math Assignments', items: [5] }
492
913
  }}
493
914
  items={{
494
- 1: { id: 1, name: "Addition Worksheet" },
495
- 2: { id: 2, name: "Subtraction Worksheet" },
496
- 3: { id: 3, name: "General Questions" },
497
- 4: { id: 4, name: "Vogon Poetry" },
498
- 5: { id: 5, name: "Bistromath", descriptor: "Explain the Bistromathic Drive" }
915
+ 1: { id: 1, name: 'Addition Worksheet' },
916
+ 2: { id: 2, name: 'Subtraction Worksheet' },
917
+ 3: { id: 3, name: 'General Questions' },
918
+ 4: { id: 4, name: 'Vogon Poetry' },
919
+ 5: {
920
+ id: 5,
921
+ name: 'Bistromath',
922
+ descriptor: 'Explain the Bistromathic Drive'
923
+ }
499
924
  }}
500
925
  defaultExpanded={[1, 3]}
501
926
  rootId={1}
502
- sortOrder={this.state.sorted? (a,b)=>{return(a.name).localeCompare(b.name)}: (a,b)=>{return 0} }
927
+ sortOrder={sorted ? (a, b) => a.name.localeCompare(b.name) : () => 0}
503
928
  />
504
929
  </>
505
930
  )
506
931
  }
507
- }
508
932
 
509
- render(<Example/>)
510
-
511
- ```
933
+ render(<Example />)
934
+ ```
512
935
 
513
936
  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`)
514
937
 
515
- ```js
516
- ---
517
- type: example
518
- ---
519
- class Example extends React.Component {
520
- constructor (props) {
521
- super(props)
522
- this.state = {
523
- size: 'medium'
938
+ - ```js
939
+ class Example extends React.Component {
940
+ constructor(props) {
941
+ super(props)
942
+ this.state = {
943
+ size: 'medium'
944
+ }
524
945
  }
525
- }
526
- render () {
527
- return (
946
+ render() {
947
+ return (
528
948
  <TreeBrowser
529
949
  size={this.state.size}
530
950
  collections={{
531
951
  1: {
532
952
  id: 1,
533
- name: "Assignments",
534
- collections: [3,2],
953
+ name: 'Assignments',
954
+ collections: [3, 2],
535
955
  items: [3],
536
- descriptor: "Class Assignments",
956
+ descriptor: 'Class Assignments',
537
957
  // Sort the direct children of "Assignment" by their name in alphabetical order
538
- compareFunc: (a,b)=>{return a.name.localeCompare(b.name)}
539
- },
540
- 2: { id: 2, name: "English Assignments", collections: [4], items: [] },
541
- 3: { id: 3, name: "Math Assignments", collections: [5], items: [2,1],
542
- // The items appear before subcollections
543
- compareFunc: (a,b)=>{
544
- if(a.type === "item" && b.type === "collection"){
545
- return -1
958
+ compareFunc: (a, b) => {
959
+ return a.name.localeCompare(b.name)
546
960
  }
547
- if(a.type === "collection" && b.type === "item"){
548
- return 1
961
+ },
962
+ 2: {
963
+ id: 2,
964
+ name: 'English Assignments',
965
+ collections: [4],
966
+ items: []
967
+ },
968
+ 3: {
969
+ id: 3,
970
+ name: 'Math Assignments',
971
+ collections: [5],
972
+ items: [2, 1],
973
+ // The items appear before subcollections
974
+ compareFunc: (a, b) => {
975
+ if (a.type === 'item' && b.type === 'collection') {
976
+ return -1
977
+ }
978
+ if (a.type === 'collection' && b.type === 'item') {
979
+ return 1
980
+ }
981
+ return 0
549
982
  }
550
- return 0
551
- }},
552
- 4: { id: 4, name: "Reading Assignments", collections: [], items: [4] },
553
- 5: { id: 5, name: "Advanced Math Assignments", items: [5]}
983
+ },
984
+ 4: {
985
+ id: 4,
986
+ name: 'Reading Assignments',
987
+ collections: [],
988
+ items: [4]
989
+ },
990
+ 5: { id: 5, name: 'Advanced Math Assignments', items: [5] }
554
991
  }}
555
992
  items={{
556
- 1: { id: 1, name: "Addition Worksheet" },
557
- 2: { id: 2, name: "Subtraction Worksheet" },
558
- 3: { id: 3, name: "General Questions" },
559
- 4: { id: 4, name: "Vogon Poetry" },
560
- 5: { id: 5, name: "Bistromath", descriptor: "Explain the Bistromathic Drive" }
993
+ 1: { id: 1, name: 'Addition Worksheet' },
994
+ 2: { id: 2, name: 'Subtraction Worksheet' },
995
+ 3: { id: 3, name: 'General Questions' },
996
+ 4: { id: 4, name: 'Vogon Poetry' },
997
+ 5: {
998
+ id: 5,
999
+ name: 'Bistromath',
1000
+ descriptor: 'Explain the Bistromathic Drive'
1001
+ }
561
1002
  }}
562
1003
  defaultExpanded={[1, 3]}
563
1004
  rootId={1}
564
1005
  />
565
- )
1006
+ )
1007
+ }
566
1008
  }
567
- }
568
1009
 
569
- render(<Example/>)
1010
+ render(<Example />)
1011
+ ```
570
1012
 
571
- ```
1013
+ - ```js
1014
+ const Example = () => {
1015
+ const [size, setSize] = useState('medium')
1016
+
1017
+ return (
1018
+ <TreeBrowser
1019
+ size={size}
1020
+ collections={{
1021
+ 1: {
1022
+ id: 1,
1023
+ name: 'Assignments',
1024
+ collections: [3, 2],
1025
+ items: [3],
1026
+ descriptor: 'Class Assignments',
1027
+ // Sort the direct children of "Assignment" by their name in alphabetical order
1028
+ compareFunc: (a, b) => a.name.localeCompare(b.name)
1029
+ },
1030
+ 2: {
1031
+ id: 2,
1032
+ name: 'English Assignments',
1033
+ collections: [4],
1034
+ items: []
1035
+ },
1036
+ 3: {
1037
+ id: 3,
1038
+ name: 'Math Assignments',
1039
+ collections: [5],
1040
+ items: [2, 1],
1041
+ // The items appear before subcollections
1042
+ compareFunc: (a, b) => {
1043
+ if (a.type === 'item' && b.type === 'collection') {
1044
+ return -1
1045
+ }
1046
+ if (a.type === 'collection' && b.type === 'item') {
1047
+ return 1
1048
+ }
1049
+ return 0
1050
+ }
1051
+ },
1052
+ 4: {
1053
+ id: 4,
1054
+ name: 'Reading Assignments',
1055
+ collections: [],
1056
+ items: [4]
1057
+ },
1058
+ 5: { id: 5, name: 'Advanced Math Assignments', items: [5] }
1059
+ }}
1060
+ items={{
1061
+ 1: { id: 1, name: 'Addition Worksheet' },
1062
+ 2: { id: 2, name: 'Subtraction Worksheet' },
1063
+ 3: { id: 3, name: 'General Questions' },
1064
+ 4: { id: 4, name: 'Vogon Poetry' },
1065
+ 5: {
1066
+ id: 5,
1067
+ name: 'Bistromath',
1068
+ descriptor: 'Explain the Bistromathic Drive'
1069
+ }
1070
+ }}
1071
+ defaultExpanded={[1, 3]}
1072
+ rootId={1}
1073
+ />
1074
+ )
1075
+ }
1076
+
1077
+ render(<Example />)
1078
+ ```
572
1079
 
573
1080
  ### showRootCollection
574
1081
 
575
1082
  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`.
576
1083
 
577
- ```js
578
- ---
579
- type: example
580
- ---
581
- class Example extends React.Component {
582
- constructor (props) {
583
- super(props)
584
- this.state = {
585
- showRootCollection: true
1084
+ - ```js
1085
+ class Example extends React.Component {
1086
+ constructor(props) {
1087
+ super(props)
1088
+ this.state = {
1089
+ showRootCollection: true
1090
+ }
586
1091
  }
587
- }
588
1092
 
589
- handleSwitch = () => {
590
- this.setState({ showRootCollection: !this.state.showRootCollection })
591
- }
1093
+ handleSwitch = () => {
1094
+ this.setState({ showRootCollection: !this.state.showRootCollection })
1095
+ }
592
1096
 
593
- renderNode = () => {
594
- return (
595
- <TreeBrowser.Node itemIcon={<IconPlusLine />}>
596
- More
597
- </TreeBrowser.Node>
598
- )
1097
+ renderNode = () => {
1098
+ return (
1099
+ <TreeBrowser.Node itemIcon={<IconPlusLine />}>More</TreeBrowser.Node>
1100
+ )
1101
+ }
1102
+
1103
+ render() {
1104
+ return (
1105
+ <>
1106
+ <View display="block" margin="none none medium">
1107
+ <Checkbox
1108
+ label="showRootCollection"
1109
+ variant="toggle"
1110
+ size="medium"
1111
+ checked={this.state.showRootCollection}
1112
+ onChange={this.handleSwitch}
1113
+ />
1114
+ </View>
1115
+
1116
+ <TreeBrowser
1117
+ collections={{
1118
+ 1: {
1119
+ id: 1,
1120
+ name: 'Assignments',
1121
+ collections: [2, 3],
1122
+ items: [3, 5],
1123
+ descriptor: 'Class Assignments',
1124
+ renderAfterItems: this.renderNode()
1125
+ },
1126
+ 2: {
1127
+ id: 2,
1128
+ name: 'English Assignments',
1129
+ collections: [4],
1130
+ items: []
1131
+ },
1132
+ 3: {
1133
+ id: 3,
1134
+ name: 'Math Assignments',
1135
+ collections: [5],
1136
+ items: [1, 2]
1137
+ },
1138
+ 4: {
1139
+ id: 4,
1140
+ name: 'Reading Assignments',
1141
+ collections: [],
1142
+ items: [4]
1143
+ },
1144
+ 5: { id: 5, name: 'Advanced Math Assignments', items: [5] }
1145
+ }}
1146
+ items={{
1147
+ 1: { id: 1, name: 'Addition Worksheet' },
1148
+ 2: { id: 2, name: 'Subtraction Worksheet' },
1149
+ 3: { id: 3, name: 'General Questions' },
1150
+ 4: { id: 4, name: 'Vogon Poetry' },
1151
+ 5: {
1152
+ id: 5,
1153
+ name: 'Bistromath',
1154
+ descriptor: 'Explain the Bistromathic Drive'
1155
+ }
1156
+ }}
1157
+ defaultExpanded={[1, 3]}
1158
+ rootId={1}
1159
+ showRootCollection={this.state.showRootCollection}
1160
+ />
1161
+ </>
1162
+ )
1163
+ }
599
1164
  }
600
1165
 
601
- render () {
1166
+ render(<Example />)
1167
+ ```
1168
+
1169
+ - ```js
1170
+ const Example = () => {
1171
+ const [showRootCollection, setShowRootCollection] = useState(true)
1172
+
1173
+ const handleSwitch = () => {
1174
+ setShowRootCollection(!showRootCollection)
1175
+ }
1176
+
1177
+ const renderNode = () => {
1178
+ return (
1179
+ <TreeBrowser.Node itemIcon={<IconPlusLine />}>More</TreeBrowser.Node>
1180
+ )
1181
+ }
1182
+
602
1183
  return (
603
1184
  <>
604
1185
  <View display="block" margin="none none medium">
@@ -606,8 +1187,8 @@ class Example extends React.Component {
606
1187
  label="showRootCollection"
607
1188
  variant="toggle"
608
1189
  size="medium"
609
- checked={this.state.showRootCollection}
610
- onChange={this.handleSwitch}
1190
+ checked={showRootCollection}
1191
+ onChange={handleSwitch}
611
1192
  />
612
1193
  </View>
613
1194
 
@@ -615,36 +1196,53 @@ class Example extends React.Component {
615
1196
  collections={{
616
1197
  1: {
617
1198
  id: 1,
618
- name: "Assignments",
619
- collections: [2,3],
1199
+ name: 'Assignments',
1200
+ collections: [2, 3],
620
1201
  items: [3, 5],
621
- descriptor: "Class Assignments",
622
- renderAfterItems: this.renderNode()
1202
+ descriptor: 'Class Assignments',
1203
+ renderAfterItems: renderNode()
1204
+ },
1205
+ 2: {
1206
+ id: 2,
1207
+ name: 'English Assignments',
1208
+ collections: [4],
1209
+ items: []
1210
+ },
1211
+ 3: {
1212
+ id: 3,
1213
+ name: 'Math Assignments',
1214
+ collections: [5],
1215
+ items: [1, 2]
623
1216
  },
624
- 2: { id: 2, name: "English Assignments", collections: [4], items: [] },
625
- 3: { id: 3, name: "Math Assignments", collections: [5], items: [1,2] },
626
- 4: { id: 4, name: "Reading Assignments", collections: [], items: [4] },
627
- 5: { id: 5, name: "Advanced Math Assignments", items: [5]}
1217
+ 4: {
1218
+ id: 4,
1219
+ name: 'Reading Assignments',
1220
+ collections: [],
1221
+ items: [4]
1222
+ },
1223
+ 5: { id: 5, name: 'Advanced Math Assignments', items: [5] }
628
1224
  }}
629
1225
  items={{
630
- 1: { id: 1, name: "Addition Worksheet" },
631
- 2: { id: 2, name: "Subtraction Worksheet" },
632
- 3: { id: 3, name: "General Questions" },
633
- 4: { id: 4, name: "Vogon Poetry" },
634
- 5: { id: 5, name: "Bistromath", descriptor: "Explain the Bistromathic Drive" }
1226
+ 1: { id: 1, name: 'Addition Worksheet' },
1227
+ 2: { id: 2, name: 'Subtraction Worksheet' },
1228
+ 3: { id: 3, name: 'General Questions' },
1229
+ 4: { id: 4, name: 'Vogon Poetry' },
1230
+ 5: {
1231
+ id: 5,
1232
+ name: 'Bistromath',
1233
+ descriptor: 'Explain the Bistromathic Drive'
1234
+ }
635
1235
  }}
636
1236
  defaultExpanded={[1, 3]}
637
1237
  rootId={1}
638
- showRootCollection={this.state.showRootCollection}
1238
+ showRootCollection={showRootCollection}
639
1239
  />
640
1240
  </>
641
1241
  )
642
1242
  }
643
- }
644
-
645
- render(<Example/>)
646
1243
 
647
- ```
1244
+ render(<Example />)
1245
+ ```
648
1246
 
649
1247
  ### Guidelines
650
1248