@instructure/ui-tree-browser 8.14.1-snapshot.7 → 8.15.1-snapshot.2
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 +4 -0
- package/es/TreeBrowser/TreeBrowserLocator.js +2 -1
- package/es/TreeBrowser/TreeButton/index.js +14 -15
- package/es/TreeBrowser/TreeCollection/index.js +18 -31
- package/es/TreeBrowser/TreeCollection/props.js +1 -9
- package/es/TreeBrowser/TreeNode/index.js +10 -13
- package/es/TreeBrowser/TreeNode/props.js +0 -8
- package/es/TreeBrowser/index.js +36 -32
- package/es/TreeBrowser/props.js +0 -55
- package/lib/TreeBrowser/TreeBrowserLocator.js +2 -1
- package/lib/TreeBrowser/TreeButton/index.js +14 -14
- package/lib/TreeBrowser/TreeCollection/index.js +17 -30
- package/lib/TreeBrowser/TreeCollection/props.js +1 -9
- package/lib/TreeBrowser/TreeNode/index.js +10 -12
- package/lib/TreeBrowser/TreeNode/props.js +0 -8
- package/lib/TreeBrowser/index.js +37 -33
- package/lib/TreeBrowser/props.js +0 -55
- package/package.json +15 -15
- package/src/TreeBrowser/TreeButton/index.tsx +21 -36
- package/src/TreeBrowser/TreeButton/props.ts +11 -10
- package/src/TreeBrowser/TreeCollection/index.tsx +57 -108
- package/src/TreeBrowser/TreeCollection/props.ts +17 -32
- package/src/TreeBrowser/TreeNode/index.tsx +10 -21
- package/src/TreeBrowser/TreeNode/props.ts +5 -7
- package/src/TreeBrowser/index.tsx +81 -108
- package/src/TreeBrowser/props.ts +133 -59
- package/tsconfig.build.tsbuildinfo +1 -1
- package/types/TreeBrowser/TreeBrowserLocator.d.ts +14 -14
- package/types/TreeBrowser/TreeButton/index.d.ts +5 -51
- package/types/TreeBrowser/TreeButton/index.d.ts.map +1 -1
- package/types/TreeBrowser/TreeButton/props.d.ts +11 -10
- package/types/TreeBrowser/TreeButton/props.d.ts.map +1 -1
- package/types/TreeBrowser/TreeCollection/index.d.ts +33 -85
- package/types/TreeBrowser/TreeCollection/index.d.ts.map +1 -1
- package/types/TreeBrowser/TreeCollection/props.d.ts +11 -25
- package/types/TreeBrowser/TreeCollection/props.d.ts.map +1 -1
- package/types/TreeBrowser/TreeNode/index.d.ts +4 -12
- package/types/TreeBrowser/TreeNode/index.d.ts.map +1 -1
- package/types/TreeBrowser/TreeNode/props.d.ts +5 -1
- package/types/TreeBrowser/TreeNode/props.d.ts.map +1 -1
- package/types/TreeBrowser/index.d.ts +35 -73
- package/types/TreeBrowser/index.d.ts.map +1 -1
- package/types/TreeBrowser/props.d.ts +113 -16
- package/types/TreeBrowser/props.d.ts.map +1 -1
|
@@ -24,12 +24,12 @@
|
|
|
24
24
|
|
|
25
25
|
/** @jsx jsx */
|
|
26
26
|
|
|
27
|
-
import { Component } from 'react'
|
|
27
|
+
import { Component, SyntheticEvent } from 'react'
|
|
28
28
|
import keycode from 'keycode'
|
|
29
29
|
|
|
30
30
|
import { IconFolderLine, IconDocumentLine } from '@instructure/ui-icons'
|
|
31
31
|
|
|
32
|
-
import {
|
|
32
|
+
import { omitProps, pickProps } from '@instructure/ui-react-utils'
|
|
33
33
|
import { testable } from '@instructure/ui-testable'
|
|
34
34
|
import { withStyle, jsx } from '@instructure/emotion'
|
|
35
35
|
|
|
@@ -39,17 +39,24 @@ import { TreeNode } from './TreeNode'
|
|
|
39
39
|
|
|
40
40
|
import generateStyles from './styles'
|
|
41
41
|
import generateComponentTheme from './theme'
|
|
42
|
-
import type {
|
|
42
|
+
import type {
|
|
43
|
+
Collection,
|
|
44
|
+
CollectionData,
|
|
45
|
+
CollectionProps,
|
|
46
|
+
TreeBrowserProps,
|
|
47
|
+
TreeBrowserState
|
|
48
|
+
} from './props'
|
|
43
49
|
import { allowedProps, propTypes } from './props'
|
|
44
50
|
|
|
45
51
|
/**
|
|
46
52
|
---
|
|
47
53
|
category: components
|
|
48
54
|
---
|
|
55
|
+
@tsProps
|
|
49
56
|
**/
|
|
50
57
|
@withStyle(generateStyles, generateComponentTheme)
|
|
51
58
|
@testable()
|
|
52
|
-
class TreeBrowser extends Component<TreeBrowserProps> {
|
|
59
|
+
class TreeBrowser extends Component<TreeBrowserProps, TreeBrowserState> {
|
|
53
60
|
static readonly componentId = 'TreeBrowser'
|
|
54
61
|
|
|
55
62
|
static allowedProps = allowedProps
|
|
@@ -62,20 +69,11 @@ class TreeBrowser extends Component<TreeBrowserProps> {
|
|
|
62
69
|
collectionIcon: IconFolderLine,
|
|
63
70
|
collectionIconExpanded: IconFolderLine,
|
|
64
71
|
itemIcon: IconDocumentLine,
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'props' implicitly has an 'any' type.
|
|
68
|
-
getCollectionProps: (props) => props,
|
|
72
|
+
getItemProps: (props: unknown) => props,
|
|
73
|
+
getCollectionProps: (props: unknown) => props,
|
|
69
74
|
defaultExpanded: [],
|
|
70
75
|
selectionType: 'none',
|
|
71
|
-
|
|
72
|
-
onItemClick: function (item) {},
|
|
73
|
-
// @ts-expect-error ts-migrate(6133) FIXME: 'id' is declared but its value is never read.
|
|
74
|
-
onCollectionClick: function (id, collection) {},
|
|
75
|
-
// @ts-expect-error ts-migrate(6133) FIXME: 'collection' is declared but its value is never re... Remove this comment to see the full error message
|
|
76
|
-
onCollectionToggle: function (collection) {},
|
|
77
|
-
// @ts-expect-error ts-migrate(6133) FIXME: 'foo' and 'bar' are declared but their values are never read.
|
|
78
|
-
sortOrder: function (obj1, obj2) {
|
|
76
|
+
sortOrder: function () {
|
|
79
77
|
return 0
|
|
80
78
|
}
|
|
81
79
|
}
|
|
@@ -83,55 +81,53 @@ class TreeBrowser extends Component<TreeBrowserProps> {
|
|
|
83
81
|
static Node = TreeNode
|
|
84
82
|
static Collection = TreeCollection
|
|
85
83
|
static Button = TreeButton
|
|
84
|
+
|
|
86
85
|
ref: Element | null = null
|
|
87
86
|
|
|
88
|
-
|
|
89
|
-
constructor(props) {
|
|
87
|
+
constructor(props: TreeBrowserProps) {
|
|
90
88
|
super(props)
|
|
91
|
-
|
|
92
|
-
this.state = { selection: '' }
|
|
93
|
-
|
|
94
89
|
if (typeof this.props.expanded === 'undefined') {
|
|
95
|
-
|
|
96
|
-
|
|
90
|
+
this.state = { expanded: this.props.defaultExpanded, selection: '' }
|
|
91
|
+
} else {
|
|
92
|
+
this.state = { selection: '' }
|
|
97
93
|
}
|
|
98
94
|
}
|
|
95
|
+
|
|
99
96
|
componentDidMount() {
|
|
100
97
|
this.props.makeStyles?.()
|
|
101
98
|
}
|
|
99
|
+
|
|
102
100
|
componentDidUpdate() {
|
|
103
101
|
this.props.makeStyles?.()
|
|
104
102
|
}
|
|
103
|
+
|
|
105
104
|
get _root() {
|
|
106
105
|
console.warn(
|
|
107
106
|
'_root property is deprecated and will be removed in v9, please use ref instead'
|
|
108
107
|
)
|
|
109
|
-
|
|
110
108
|
return this.ref
|
|
111
109
|
}
|
|
112
110
|
|
|
113
|
-
|
|
114
|
-
|
|
111
|
+
handleCollectionClick = (
|
|
112
|
+
e: SyntheticEvent,
|
|
113
|
+
collection: CollectionData,
|
|
114
|
+
expand = true
|
|
115
|
+
) => {
|
|
115
116
|
e.stopPropagation()
|
|
116
117
|
const { onCollectionClick } = this.props
|
|
117
118
|
|
|
118
119
|
if (expand) this.expandOrCollapseNode(collection)
|
|
119
|
-
|
|
120
|
-
onCollectionClick(collection.id, collection) // TODO: this should pass the event as the first arg
|
|
120
|
+
onCollectionClick?.(collection.id as any, collection) // TODO: this should pass the event as the first arg
|
|
121
121
|
this.handleSelection(collection.id, 'collection')
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
|
|
125
|
-
handleItemClick = (e, item) => {
|
|
124
|
+
handleItemClick = (e: SyntheticEvent, item: CollectionData) => {
|
|
126
125
|
e.stopPropagation()
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
onItemClick(item)
|
|
130
|
-
this.handleSelection(item.id, 'item') // TODO: this should pass the event as the first arg
|
|
126
|
+
this.props.onItemClick?.(item)
|
|
127
|
+
this.handleSelection(item.id, 'item')
|
|
131
128
|
}
|
|
132
129
|
|
|
133
|
-
|
|
134
|
-
handleKeyDown = (event, node) => {
|
|
130
|
+
handleKeyDown = (event: React.KeyboardEvent, node?: CollectionData) => {
|
|
135
131
|
event.stopPropagation()
|
|
136
132
|
switch (event.keyCode) {
|
|
137
133
|
case keycode.codes.down:
|
|
@@ -162,7 +158,6 @@ class TreeBrowser extends Component<TreeBrowserProps> {
|
|
|
162
158
|
|
|
163
159
|
get collections() {
|
|
164
160
|
const { collections, rootId } = this.props
|
|
165
|
-
|
|
166
161
|
if (typeof rootId !== 'undefined') {
|
|
167
162
|
return [collections[rootId]]
|
|
168
163
|
} else {
|
|
@@ -176,42 +171,33 @@ class TreeBrowser extends Component<TreeBrowserProps> {
|
|
|
176
171
|
return this.getExpanded(this.state, this.props)
|
|
177
172
|
}
|
|
178
173
|
|
|
179
|
-
|
|
180
|
-
getExpanded(state, props) {
|
|
174
|
+
getExpanded(state: TreeBrowserState, props: TreeBrowserProps) {
|
|
181
175
|
return typeof props.expanded === 'undefined'
|
|
182
|
-
? state.expanded
|
|
176
|
+
? state.expanded!
|
|
183
177
|
: props.expanded
|
|
184
178
|
}
|
|
185
179
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
// @ts-expect-error ts-migrate(2722) FIXME: Cannot invoke an object which is possibly 'undefin... Remove this comment to see the full error message
|
|
189
|
-
this.props.onCollectionToggle(collection)
|
|
180
|
+
expandOrCollapseNode(collection: CollectionData) {
|
|
181
|
+
this.props.onCollectionToggle?.(collection)
|
|
190
182
|
if (typeof this.props.expanded === 'undefined') {
|
|
191
183
|
this.setState((state, props) => {
|
|
192
|
-
const expanded = [
|
|
193
|
-
|
|
184
|
+
const expanded = [...this.getExpanded(state, props)]
|
|
194
185
|
const expandedIndex = this.getExpandedIndex(expanded, collection.id)
|
|
195
|
-
|
|
196
186
|
if (collection.expanded && expandedIndex < 0) {
|
|
197
|
-
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'any' is not assignable to parame... Remove this comment to see the full error message
|
|
198
187
|
expanded.push(collection.id)
|
|
199
188
|
} else if (expandedIndex >= 0) {
|
|
200
189
|
expanded.splice(expandedIndex, 1)
|
|
201
190
|
}
|
|
202
|
-
|
|
203
191
|
return { expanded }
|
|
204
192
|
})
|
|
205
193
|
}
|
|
206
194
|
}
|
|
207
195
|
|
|
208
|
-
|
|
209
|
-
handleSelection(id, type) {
|
|
196
|
+
handleSelection(id: string | number | undefined, type: string) {
|
|
210
197
|
const { selectionType } = this.props
|
|
211
198
|
selectionType === 'single' &&
|
|
212
199
|
this.setState((state) => {
|
|
213
200
|
const selection = `${type}_${id}`
|
|
214
|
-
// @ts-expect-error ts-migrate(2339) FIXME: Property 'selection' does not exist on type 'Reado... Remove this comment to see the full error message
|
|
215
201
|
if (state.selection !== selection) {
|
|
216
202
|
return { selection }
|
|
217
203
|
} else {
|
|
@@ -224,12 +210,10 @@ class TreeBrowser extends Component<TreeBrowserProps> {
|
|
|
224
210
|
return Array.from(this.ref!.querySelectorAll('[role="treeitem"]'))
|
|
225
211
|
}
|
|
226
212
|
|
|
227
|
-
|
|
228
|
-
moveFocus(delta) {
|
|
213
|
+
moveFocus(delta: number) {
|
|
229
214
|
const nodes = this.getNavigableNodes()
|
|
230
|
-
|
|
231
|
-
const
|
|
232
|
-
const active = nodes.indexOf(closest!)
|
|
215
|
+
const closest = window.document.activeElement!.closest('[role="treeitem"]')!
|
|
216
|
+
const active = nodes.indexOf(closest)
|
|
233
217
|
let next = active + delta
|
|
234
218
|
if (next < 0) {
|
|
235
219
|
next = 0
|
|
@@ -240,12 +224,10 @@ class TreeBrowser extends Component<TreeBrowserProps> {
|
|
|
240
224
|
n.setAttribute('tabindex', '-1')
|
|
241
225
|
})
|
|
242
226
|
nodes[next].setAttribute('tabindex', '0')
|
|
243
|
-
|
|
244
|
-
nodes[next].focus()
|
|
227
|
+
;(nodes[next] as any).focus()
|
|
245
228
|
}
|
|
246
229
|
|
|
247
|
-
|
|
248
|
-
homeOrEnd(keyCode) {
|
|
230
|
+
homeOrEnd(keyCode: number) {
|
|
249
231
|
const length = this.getNavigableNodes().length
|
|
250
232
|
if (keyCode === keycode.codes.home) {
|
|
251
233
|
this.moveFocus(1 - length)
|
|
@@ -254,11 +236,9 @@ class TreeBrowser extends Component<TreeBrowserProps> {
|
|
|
254
236
|
}
|
|
255
237
|
}
|
|
256
238
|
|
|
257
|
-
|
|
258
|
-
handleLeftOrRightArrow(keyCode, node) {
|
|
239
|
+
handleLeftOrRightArrow(keyCode: number, node?: CollectionData) {
|
|
259
240
|
const ltr = !(
|
|
260
|
-
|
|
261
|
-
(this.ref.parentElement.dir === 'rtl' || document.dir === 'rtl')
|
|
241
|
+
this.ref!.parentElement!.dir === 'rtl' || document.dir === 'rtl'
|
|
262
242
|
)
|
|
263
243
|
if (
|
|
264
244
|
(ltr && keyCode === keycode.codes.left) ||
|
|
@@ -270,8 +250,7 @@ class TreeBrowser extends Component<TreeBrowserProps> {
|
|
|
270
250
|
}
|
|
271
251
|
}
|
|
272
252
|
|
|
273
|
-
|
|
274
|
-
handleOpenOrNext(node) {
|
|
253
|
+
handleOpenOrNext(node?: CollectionData) {
|
|
275
254
|
if (
|
|
276
255
|
node &&
|
|
277
256
|
!this.expanded.includes(node.id) &&
|
|
@@ -283,8 +262,7 @@ class TreeBrowser extends Component<TreeBrowserProps> {
|
|
|
283
262
|
}
|
|
284
263
|
}
|
|
285
264
|
|
|
286
|
-
|
|
287
|
-
handleCloseOrPrevious(node) {
|
|
265
|
+
handleCloseOrPrevious(node?: CollectionData) {
|
|
288
266
|
if (node && this.expanded.includes(node.id) && node.type === 'collection') {
|
|
289
267
|
this.expandOrCollapseNode(node)
|
|
290
268
|
} else {
|
|
@@ -292,8 +270,7 @@ class TreeBrowser extends Component<TreeBrowserProps> {
|
|
|
292
270
|
}
|
|
293
271
|
}
|
|
294
272
|
|
|
295
|
-
|
|
296
|
-
handleActivation(event, node) {
|
|
273
|
+
handleActivation(event: React.KeyboardEvent, node?: CollectionData) {
|
|
297
274
|
if (node == null) return
|
|
298
275
|
if (node.type === 'collection') {
|
|
299
276
|
this.handleCollectionClick(
|
|
@@ -306,21 +283,19 @@ class TreeBrowser extends Component<TreeBrowserProps> {
|
|
|
306
283
|
}
|
|
307
284
|
}
|
|
308
285
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
286
|
+
getSubCollections(collection: Collection) {
|
|
287
|
+
const collections = collection.collections
|
|
288
|
+
? [...collection.collections]
|
|
289
|
+
: []
|
|
313
290
|
return collections
|
|
314
291
|
.map((id) => this.getCollectionProps(this.props.collections[id]))
|
|
315
292
|
.filter((collection) => collection != null)
|
|
316
293
|
.sort(this.props.sortOrder)
|
|
317
294
|
}
|
|
318
295
|
|
|
319
|
-
|
|
320
|
-
getItems(collection) {
|
|
296
|
+
getItems(collection: Collection) {
|
|
321
297
|
if (collection.items) {
|
|
322
|
-
const items = [
|
|
323
|
-
|
|
298
|
+
const items = collection.items ? [...collection.items] : []
|
|
324
299
|
return items
|
|
325
300
|
.map((id) => {
|
|
326
301
|
return { ...this.props.items[id] }
|
|
@@ -332,8 +307,7 @@ class TreeBrowser extends Component<TreeBrowserProps> {
|
|
|
332
307
|
}
|
|
333
308
|
}
|
|
334
309
|
|
|
335
|
-
|
|
336
|
-
getIsFlattened = (collection) => {
|
|
310
|
+
getIsFlattened = (collection: Collection) => {
|
|
337
311
|
const { rootId, showRootCollection } = this.props
|
|
338
312
|
return (
|
|
339
313
|
!showRootCollection &&
|
|
@@ -342,46 +316,46 @@ class TreeBrowser extends Component<TreeBrowserProps> {
|
|
|
342
316
|
)
|
|
343
317
|
}
|
|
344
318
|
|
|
345
|
-
|
|
346
|
-
getCollectionProps(collection) {
|
|
319
|
+
getCollectionProps(collection: Collection): CollectionProps {
|
|
347
320
|
return {
|
|
348
321
|
id: collection.id,
|
|
349
322
|
name: collection.name,
|
|
350
|
-
descriptor: collection.descriptor,
|
|
351
|
-
expanded: this.getExpandedIndex(this.expanded, collection.id) >= 0,
|
|
352
|
-
items: this.getItems(collection),
|
|
353
323
|
collections: this.getSubCollections(collection),
|
|
324
|
+
items: this.getItems(collection),
|
|
325
|
+
descriptor: collection.descriptor,
|
|
326
|
+
containerRef: collection.containerRef,
|
|
354
327
|
renderBeforeItems: collection.renderBeforeItems,
|
|
355
328
|
renderAfterItems: collection.renderAfterItems,
|
|
356
|
-
|
|
329
|
+
expanded: this.getExpandedIndex(this.expanded, collection.id) >= 0,
|
|
357
330
|
isCollectionFlattened: this.getIsFlattened(collection)
|
|
358
331
|
}
|
|
359
332
|
}
|
|
360
333
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
334
|
+
getExpandedIndex(
|
|
335
|
+
expanded: (string | number | undefined)[],
|
|
336
|
+
id?: string | number
|
|
337
|
+
) {
|
|
364
338
|
return expanded.findIndex((expanded) => String(expanded) === String(id))
|
|
365
339
|
}
|
|
366
340
|
|
|
367
341
|
renderRoot() {
|
|
368
|
-
return this.collections
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
342
|
+
return this.collections
|
|
343
|
+
.sort(this.props.sortOrder)
|
|
344
|
+
.map((collection, i) => (
|
|
345
|
+
<TreeCollection
|
|
346
|
+
key={i}
|
|
347
|
+
{...pickProps(omitProps(this.props), TreeCollection.allowedProps)}
|
|
348
|
+
{...this.getCollectionProps(collection)}
|
|
349
|
+
selection={this.state.selection}
|
|
350
|
+
onItemClick={this.handleItemClick}
|
|
351
|
+
onCollectionClick={this.handleCollectionClick}
|
|
352
|
+
onKeyDown={this.handleKeyDown}
|
|
353
|
+
numChildren={this.collections.length}
|
|
354
|
+
level={1}
|
|
355
|
+
position={1}
|
|
356
|
+
renderContent={this.props.renderContent}
|
|
357
|
+
/>
|
|
358
|
+
))
|
|
385
359
|
}
|
|
386
360
|
|
|
387
361
|
render() {
|
|
@@ -392,7 +366,6 @@ class TreeBrowser extends Component<TreeBrowserProps> {
|
|
|
392
366
|
css={styles?.treeBrowser}
|
|
393
367
|
tabIndex={0}
|
|
394
368
|
role="tree"
|
|
395
|
-
// @ts-expect-error ts-migrate(2322) FIXME: Type '(event: any, node: any) => void' is not assi... Remove this comment to see the full error message
|
|
396
369
|
onKeyDown={this.handleKeyDown}
|
|
397
370
|
ref={(el) => {
|
|
398
371
|
this.ref = el
|
package/src/TreeBrowser/props.ts
CHANGED
|
@@ -31,28 +31,88 @@ import type {
|
|
|
31
31
|
TreeBrowserTheme
|
|
32
32
|
} from '@instructure/shared-types'
|
|
33
33
|
import type { WithStyleProps, ComponentStyle } from '@instructure/emotion'
|
|
34
|
+
import React, { ReactElement } from 'react'
|
|
35
|
+
import type { TreeBrowserButtonProps } from './TreeButton/props'
|
|
34
36
|
|
|
35
37
|
type TreeBrowserOwnProps = {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
+
/**
|
|
39
|
+
* a normalized hash of collections, keyed by id, that contains an
|
|
40
|
+
* :id, :name, :items (an array of item ids), :collections (an array of
|
|
41
|
+
* collection ids), optional :descriptor text, optional :containerRef function,
|
|
42
|
+
* an optional :renderBeforeItems TreeNode, and an optional :renderAfterItems TreeNode.
|
|
43
|
+
* Each collection must have a unique id.
|
|
44
|
+
*/
|
|
45
|
+
collections: Record<number | string, Collection>
|
|
46
|
+
/**
|
|
47
|
+
* a hash of items, keyed by id, that contain an :id, :name,
|
|
48
|
+
* optional :descriptor text, and optional :thumbnail url
|
|
49
|
+
*/
|
|
50
|
+
items: Record<number, CollectionItem>
|
|
51
|
+
/**
|
|
52
|
+
* specifies the id of the root level collection, if present.
|
|
53
|
+
* if no root is specified, all collections will be rendered
|
|
54
|
+
* at the top level
|
|
55
|
+
**/
|
|
38
56
|
rootId?: string | number
|
|
39
|
-
|
|
57
|
+
/**
|
|
58
|
+
* an array of expanded collection ids, must be accompanied by an 'onCollectionToggle' prop
|
|
59
|
+
*/
|
|
60
|
+
expanded?: (string | number | undefined)[] // TODO: controllable( PropTypes.arrayOf( PropTypes.oneOfType([PropTypes.string, PropTypes.number]) ), 'onCollectionToggle' )
|
|
61
|
+
/**
|
|
62
|
+
* an array of collection ids to expand by default
|
|
63
|
+
*/
|
|
40
64
|
defaultExpanded?: (string | number)[]
|
|
65
|
+
/**
|
|
66
|
+
* There are 2 types of tree selection: single and multi.
|
|
67
|
+
* This is set up to allow for "multi" in the future without having to deprecate the old API.
|
|
68
|
+
*/
|
|
41
69
|
selectionType?: 'none' | 'single'
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
getCollectionProps?: (...args: any[]) => any
|
|
70
|
+
onCollectionToggle?: (collection: CollectionData) => void
|
|
71
|
+
onItemClick?: (data: CollectionData) => void
|
|
72
|
+
/**
|
|
73
|
+
* Whether or not to show the root collection specified in rootId prop or
|
|
74
|
+
* to begin with its immediate subcollections and items instead
|
|
75
|
+
*/
|
|
49
76
|
showRootCollection?: boolean
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
77
|
+
/**
|
|
78
|
+
* An optional label to assist visually impaired users
|
|
79
|
+
*/
|
|
53
80
|
treeLabel?: string
|
|
54
|
-
|
|
81
|
+
/**
|
|
82
|
+
* An optional compare function to specify order of the collections and the items
|
|
83
|
+
*/
|
|
55
84
|
sortOrder?: (obj1: any, obj2: any) => number
|
|
85
|
+
} & TreeBrowserBaseProps
|
|
86
|
+
|
|
87
|
+
// props shared between TreeBrowser, TreeCollection
|
|
88
|
+
type TreeBrowserBaseProps = {
|
|
89
|
+
/**
|
|
90
|
+
* A function called with each item's props as an argument. The return value of this function is a
|
|
91
|
+
* props object which will be passed to the item when it is rendered. This is useful for situations where
|
|
92
|
+
* you need to render the item differently depending on it's props. For example, if you would like to
|
|
93
|
+
* display a different icon for items with a certain name.
|
|
94
|
+
*/
|
|
95
|
+
getItemProps?: (props: Record<string, any>) => Record<string, any> // cant use generics here :/
|
|
96
|
+
/**
|
|
97
|
+
* A function called with each collection's props as an argument. The return value of this function is a
|
|
98
|
+
* props object which will be passed to the collection when it is rendered. This is useful for situations where
|
|
99
|
+
* you need to render the collection differently depending on it's props. For example, if you would like to
|
|
100
|
+
* display a different icon for collections with a certain name.
|
|
101
|
+
*/
|
|
102
|
+
getCollectionProps?: (props: Record<string, any>) => TreeBrowserButtonProps
|
|
103
|
+
onCollectionClick?: (e: React.MouseEvent, data: CollectionData) => void
|
|
104
|
+
} & TreeBrowserCommonProps
|
|
105
|
+
|
|
106
|
+
// props shared between TreeBrowser, TreeCollection, TreeButton
|
|
107
|
+
type TreeBrowserCommonProps = {
|
|
108
|
+
size?: 'small' | 'medium' | 'large'
|
|
109
|
+
variant?: 'folderTree' | 'indent'
|
|
110
|
+
collectionIcon?: React.ReactNode | ((props: unknown) => React.ReactNode)
|
|
111
|
+
collectionIconExpanded?:
|
|
112
|
+
| React.ReactNode
|
|
113
|
+
| ((props: unknown) => React.ReactNode)
|
|
114
|
+
itemIcon?: React.ReactNode | ((props: unknown) => React.ReactNode)
|
|
115
|
+
renderContent?: (props: TreeBrowserButtonProps) => JSX.Element
|
|
56
116
|
}
|
|
57
117
|
|
|
58
118
|
type PropKeys = keyof TreeBrowserOwnProps
|
|
@@ -66,79 +126,78 @@ type TreeBrowserProps = TreeBrowserOwnProps &
|
|
|
66
126
|
|
|
67
127
|
type TreeBrowserStyle = ComponentStyle<'treeBrowser'>
|
|
68
128
|
|
|
69
|
-
|
|
129
|
+
type CollectionBase = {
|
|
130
|
+
id: number | string
|
|
131
|
+
name: string
|
|
132
|
+
descriptor?: string
|
|
70
133
|
/**
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
* collection ids), optional :descriptor text, optional :containerRef function,
|
|
74
|
-
* an optional :renderBeforeItems TreeNode, and an optional :renderAfterItems TreeNode.
|
|
75
|
-
* Each collection must have a unique id.
|
|
134
|
+
* A function that returns a reference to the underlying HTML container
|
|
135
|
+
* @param el The DOM HTMLElement
|
|
76
136
|
*/
|
|
77
|
-
|
|
137
|
+
containerRef?: (el: HTMLElement | null) => void
|
|
78
138
|
/**
|
|
79
|
-
*
|
|
80
|
-
* optional :descriptor text, and optional :thumbnail url
|
|
139
|
+
* children of type TreeNode
|
|
81
140
|
*/
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* specifies the id of the root level collection, if present.
|
|
85
|
-
* if no root is specified, all collections will be rendered
|
|
86
|
-
* at the top level
|
|
87
|
-
**/
|
|
88
|
-
rootId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
|
141
|
+
renderBeforeItems?: ReactElement // TODO: Children.oneOf([TreeNode])
|
|
89
142
|
/**
|
|
90
|
-
*
|
|
143
|
+
* children of type TreeNode
|
|
91
144
|
*/
|
|
145
|
+
renderAfterItems?: ReactElement // TODO: Children.oneOf([TreeNode])
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
type Collection = CollectionBase & {
|
|
149
|
+
items?: number[]
|
|
150
|
+
collections?: (number | string)[]
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
type CollectionItem = {
|
|
154
|
+
id: number | string
|
|
155
|
+
name: string
|
|
156
|
+
descriptor?: string
|
|
157
|
+
thumbnail?: string
|
|
158
|
+
[key: string]: unknown // allow users to extend it
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
type CollectionProps = {
|
|
162
|
+
collections?: CollectionProps[]
|
|
163
|
+
items?: CollectionItem[]
|
|
164
|
+
expanded?: boolean
|
|
165
|
+
isCollectionFlattened?: boolean
|
|
166
|
+
} & CollectionBase
|
|
167
|
+
|
|
168
|
+
type CollectionData = {
|
|
169
|
+
id?: number | string
|
|
170
|
+
expanded?: boolean
|
|
171
|
+
type: 'child' | 'collection' | 'item'
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const propTypes: PropValidators<PropKeys> = {
|
|
175
|
+
collections: PropTypes.object.isRequired,
|
|
176
|
+
items: PropTypes.object.isRequired,
|
|
177
|
+
rootId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
|
92
178
|
expanded: controllable(
|
|
93
179
|
PropTypes.arrayOf(
|
|
94
180
|
PropTypes.oneOfType([PropTypes.string, PropTypes.number])
|
|
95
181
|
),
|
|
96
182
|
'onCollectionToggle'
|
|
97
183
|
),
|
|
98
|
-
/**
|
|
99
|
-
* an array of collection ids to expand by default
|
|
100
|
-
*/
|
|
101
184
|
defaultExpanded: PropTypes.arrayOf(
|
|
102
185
|
PropTypes.oneOfType([PropTypes.string, PropTypes.number])
|
|
103
186
|
),
|
|
104
|
-
// There are 2 types of tree selection: single and multi.
|
|
105
|
-
// This is set up to allow for "multi" in the future without having to deprecate the old API.
|
|
106
187
|
selectionType: PropTypes.oneOf(['none', 'single']),
|
|
107
188
|
size: PropTypes.oneOf(['small', 'medium', 'large']),
|
|
108
189
|
variant: PropTypes.oneOf(['folderTree', 'indent']),
|
|
109
190
|
collectionIcon: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
|
|
110
191
|
collectionIconExpanded: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
|
|
111
192
|
itemIcon: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
|
|
112
|
-
/**
|
|
113
|
-
* A function called with each item's props as an argument. The return value of this function is a
|
|
114
|
-
* props object which will be passed to the item when it is rendered. This is useful for situations where
|
|
115
|
-
* you need to render the item differently depending on it's props. For example, if you would like to
|
|
116
|
-
* display a different icon for items with a certain name.
|
|
117
|
-
*/
|
|
118
193
|
getItemProps: PropTypes.func,
|
|
119
|
-
/**
|
|
120
|
-
* A function called with each collection's props as an argument. The return value of this function is a
|
|
121
|
-
* props object which will be passed to the collection when it is rendered. This is useful for situations where
|
|
122
|
-
* you need to render the collection differently depending on it's props. For example, if you would like to
|
|
123
|
-
* display a different icon for collections with a certain name.
|
|
124
|
-
*/
|
|
125
194
|
getCollectionProps: PropTypes.func,
|
|
126
|
-
/**
|
|
127
|
-
* whether or not to show the root collection specified in rootId prop or
|
|
128
|
-
* to begin with its immediate subcollections and items instead
|
|
129
|
-
*/
|
|
130
195
|
showRootCollection: PropTypes.bool,
|
|
131
196
|
onCollectionClick: PropTypes.func,
|
|
132
197
|
onCollectionToggle: PropTypes.func,
|
|
133
198
|
onItemClick: PropTypes.func,
|
|
134
|
-
/**
|
|
135
|
-
* An optional label to assist visually impaired users
|
|
136
|
-
*/
|
|
137
199
|
treeLabel: PropTypes.string,
|
|
138
200
|
renderContent: PropTypes.func,
|
|
139
|
-
/**
|
|
140
|
-
* An optional compare function to specify order of the collections and the items
|
|
141
|
-
*/
|
|
142
201
|
sortOrder: PropTypes.func
|
|
143
202
|
}
|
|
144
203
|
|
|
@@ -165,5 +224,20 @@ const allowedProps: AllowedPropKeys = [
|
|
|
165
224
|
'sortOrder'
|
|
166
225
|
]
|
|
167
226
|
|
|
168
|
-
|
|
227
|
+
type TreeBrowserState = {
|
|
228
|
+
selection: string
|
|
229
|
+
expanded?: (string | number | undefined)[]
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export type {
|
|
233
|
+
TreeBrowserProps,
|
|
234
|
+
TreeBrowserState,
|
|
235
|
+
TreeBrowserStyle,
|
|
236
|
+
CollectionData,
|
|
237
|
+
Collection,
|
|
238
|
+
CollectionItem,
|
|
239
|
+
CollectionProps,
|
|
240
|
+
TreeBrowserBaseProps,
|
|
241
|
+
TreeBrowserCommonProps
|
|
242
|
+
}
|
|
169
243
|
export { propTypes, allowedProps }
|