@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.
Files changed (44) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/es/TreeBrowser/TreeBrowserLocator.js +2 -1
  3. package/es/TreeBrowser/TreeButton/index.js +14 -15
  4. package/es/TreeBrowser/TreeCollection/index.js +18 -31
  5. package/es/TreeBrowser/TreeCollection/props.js +1 -9
  6. package/es/TreeBrowser/TreeNode/index.js +10 -13
  7. package/es/TreeBrowser/TreeNode/props.js +0 -8
  8. package/es/TreeBrowser/index.js +36 -32
  9. package/es/TreeBrowser/props.js +0 -55
  10. package/lib/TreeBrowser/TreeBrowserLocator.js +2 -1
  11. package/lib/TreeBrowser/TreeButton/index.js +14 -14
  12. package/lib/TreeBrowser/TreeCollection/index.js +17 -30
  13. package/lib/TreeBrowser/TreeCollection/props.js +1 -9
  14. package/lib/TreeBrowser/TreeNode/index.js +10 -12
  15. package/lib/TreeBrowser/TreeNode/props.js +0 -8
  16. package/lib/TreeBrowser/index.js +37 -33
  17. package/lib/TreeBrowser/props.js +0 -55
  18. package/package.json +15 -15
  19. package/src/TreeBrowser/TreeButton/index.tsx +21 -36
  20. package/src/TreeBrowser/TreeButton/props.ts +11 -10
  21. package/src/TreeBrowser/TreeCollection/index.tsx +57 -108
  22. package/src/TreeBrowser/TreeCollection/props.ts +17 -32
  23. package/src/TreeBrowser/TreeNode/index.tsx +10 -21
  24. package/src/TreeBrowser/TreeNode/props.ts +5 -7
  25. package/src/TreeBrowser/index.tsx +81 -108
  26. package/src/TreeBrowser/props.ts +133 -59
  27. package/tsconfig.build.tsbuildinfo +1 -1
  28. package/types/TreeBrowser/TreeBrowserLocator.d.ts +14 -14
  29. package/types/TreeBrowser/TreeButton/index.d.ts +5 -51
  30. package/types/TreeBrowser/TreeButton/index.d.ts.map +1 -1
  31. package/types/TreeBrowser/TreeButton/props.d.ts +11 -10
  32. package/types/TreeBrowser/TreeButton/props.d.ts.map +1 -1
  33. package/types/TreeBrowser/TreeCollection/index.d.ts +33 -85
  34. package/types/TreeBrowser/TreeCollection/index.d.ts.map +1 -1
  35. package/types/TreeBrowser/TreeCollection/props.d.ts +11 -25
  36. package/types/TreeBrowser/TreeCollection/props.d.ts.map +1 -1
  37. package/types/TreeBrowser/TreeNode/index.d.ts +4 -12
  38. package/types/TreeBrowser/TreeNode/index.d.ts.map +1 -1
  39. package/types/TreeBrowser/TreeNode/props.d.ts +5 -1
  40. package/types/TreeBrowser/TreeNode/props.d.ts.map +1 -1
  41. package/types/TreeBrowser/index.d.ts +35 -73
  42. package/types/TreeBrowser/index.d.ts.map +1 -1
  43. package/types/TreeBrowser/props.d.ts +113 -16
  44. 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 { pickProps, omitProps } from '@instructure/ui-react-utils'
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 { TreeBrowserProps } from './props'
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
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'props' implicitly has an 'any' type.
66
- getItemProps: (props) => props,
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
- // @ts-expect-error ts-migrate(6133) FIXME: 'item' is declared but its value is never read.
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
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'props' implicitly has an 'any' type.
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
- // @ts-expect-error ts-migrate(2339) FIXME: Property 'expanded' does not exist on type 'Readon... Remove this comment to see the full error message
96
- this.state.expanded = props.defaultExpanded
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
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'e' implicitly has an 'any' type.
114
- handleCollectionClick = (e, collection, expand = true) => {
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
- // @ts-expect-error ts-migrate(2722) FIXME: Cannot invoke an object which is possibly 'undefin... Remove this comment to see the full error message
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
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'e' implicitly has an 'any' type.
125
- handleItemClick = (e, item) => {
124
+ handleItemClick = (e: SyntheticEvent, item: CollectionData) => {
126
125
  e.stopPropagation()
127
- const { onItemClick } = this.props
128
- // @ts-expect-error ts-migrate(2722) FIXME: Cannot invoke an object which is possibly 'undefin... Remove this comment to see the full error message
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
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'event' implicitly has an 'any' type.
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
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'state' implicitly has an 'any' type.
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
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'collection' implicitly has an 'any' typ... Remove this comment to see the full error message
187
- expandOrCollapseNode(collection) {
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 = [].concat(this.getExpanded(state, props))
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
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'id' implicitly has an 'any' type.
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
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'delta' implicitly has an 'any' type.
228
- moveFocus(delta) {
213
+ moveFocus(delta: number) {
229
214
  const nodes = this.getNavigableNodes()
230
- // @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
231
- const closest = window.document.activeElement.closest('[role="treeitem"]')
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
- // @ts-expect-error ts-migrate(2571) FIXME: Object is of type 'unknown'.
244
- nodes[next].focus()
227
+ ;(nodes[next] as any).focus()
245
228
  }
246
229
 
247
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'keyCode' implicitly has an 'any' type.
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
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'keyCode' implicitly has an 'any' type.
258
- handleLeftOrRightArrow(keyCode, node) {
239
+ handleLeftOrRightArrow(keyCode: number, node?: CollectionData) {
259
240
  const ltr = !(
260
- // @ts-expect-error ts-migrate(2339) FIXME: Property 'ref' is possibly null
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
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'node' implicitly has an 'any' type.
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
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'node' implicitly has an 'any' type.
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
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'event' implicitly has an 'any' type.
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
- // @ts-expect-error ts-migrate(7023) FIXME: 'getSubCollections' implicitly has return type 'an... Remove this comment to see the full error message
310
- getSubCollections(collection) {
311
- const collections = [].concat(collection.collections || [])
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
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'collection' implicitly has an 'any' typ... Remove this comment to see the full error message
320
- getItems(collection) {
296
+ getItems(collection: Collection) {
321
297
  if (collection.items) {
322
- const items = [].concat(collection.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
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'collection' implicitly has an 'any' typ... Remove this comment to see the full error message
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
- // @ts-expect-error ts-migrate(7023) FIXME: 'getCollectionProps' implicitly has return type 'a... Remove this comment to see the full error message
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
- containerRef: collection.containerRef,
329
+ expanded: this.getExpandedIndex(this.expanded, collection.id) >= 0,
357
330
  isCollectionFlattened: this.getIsFlattened(collection)
358
331
  }
359
332
  }
360
333
 
361
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'expanded' implicitly has an 'any' type.
362
- getExpandedIndex(expanded, id) {
363
- // @ts-expect-error ts-migrate(7006) FIXME: Parameter 'expanded' implicitly has an 'any' type.
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.sort(this.props.sortOrder).map((collection, i) => (
369
- <TreeCollection
370
- key={i}
371
- // @ts-expect-error ts-migrate(2554) FIXME: Expected 3 arguments, but got 2.
372
- {...pickProps(omitProps(this.props), TreeCollection.allowedProps)}
373
- {...this.getCollectionProps(collection)}
374
- // @ts-expect-error ts-migrate(2339) FIXME: Property 'selection' does not exist on type 'Reado... Remove this comment to see the full error message
375
- selection={this.state.selection}
376
- onItemClick={this.handleItemClick}
377
- onCollectionClick={this.handleCollectionClick}
378
- onKeyDown={this.handleKeyDown}
379
- numChildren={this.collections.length}
380
- level={1}
381
- position={1}
382
- renderContent={this.props.renderContent}
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
@@ -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
- collections: any
37
- items: any
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
- expanded?: any // TODO: controllable( PropTypes.arrayOf( PropTypes.oneOfType([PropTypes.string, PropTypes.number]) ), 'onCollectionToggle' )
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
- size?: 'small' | 'medium' | 'large'
43
- variant?: 'folderTree' | 'indent'
44
- collectionIcon?: React.ReactNode | ((...args: any[]) => any)
45
- collectionIconExpanded?: React.ReactNode | ((...args: any[]) => any)
46
- itemIcon?: React.ReactNode | ((...args: any[]) => any)
47
- getItemProps?: (...args: any[]) => any
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
- onCollectionClick?: (...args: any[]) => any
51
- onCollectionToggle?: (...args: any[]) => any
52
- onItemClick?: (...args: any[]) => any
77
+ /**
78
+ * An optional label to assist visually impaired users
79
+ */
53
80
  treeLabel?: string
54
- renderContent?: (...args: any[]) => any
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
- const propTypes: PropValidators<PropKeys> = {
129
+ type CollectionBase = {
130
+ id: number | string
131
+ name: string
132
+ descriptor?: string
70
133
  /**
71
- * a normalized hash of collections, keyed by id, that contain an
72
- * :id, :name, :items (an array of item ids), :collections (an array of
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
- collections: PropTypes.object.isRequired,
137
+ containerRef?: (el: HTMLElement | null) => void
78
138
  /**
79
- * a hash of items, keyed by id, that contain an :id, :name,
80
- * optional :descriptor text, and optional :thumbnail url
139
+ * children of type TreeNode
81
140
  */
82
- items: PropTypes.object.isRequired,
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
- * an array of expanded collection ids, must be accompanied by an 'onCollectionToggle' prop
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
- export type { TreeBrowserProps, TreeBrowserStyle }
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 }