4
4
* @license Open source under the MIT License
5
5
*/
6
6
7
- import React , { Component , PropTypes } from 'react' ;
8
- import { AutoSizer , List } from 'react-virtualized' ;
7
+ import React , { Component , PropTypes , cloneElement } from 'react' ;
8
+ import { AutoSizer , List , CellMeasurer , CellMeasurerCache } from 'react-virtualized' ;
9
9
import isEqual from 'lodash.isequal' ;
10
10
import withScrolling , { createVerticalStrength , createHorizontalStrength } from 'react-dnd-scrollzone' ;
11
11
import 'react-virtualized/styles.css' ;
@@ -39,6 +39,28 @@ import styles from './react-sortable-tree.scss';
39
39
40
40
let dndTypeCounter = 1 ;
41
41
42
+ const cellMeasurerCache = new CellMeasurerCache ( {
43
+ fixedWidth : true
44
+ } ) ;
45
+
46
+ const DynamicRow = ( { parent, rowIndex, children, ...extraProps } ) => (
47
+ < CellMeasurer
48
+ cache = { cellMeasurerCache }
49
+ columnIndex = { 0 }
50
+ parent = { parent }
51
+ rowIndex = { rowIndex }
52
+ >
53
+ { cloneElement ( children , extraProps ) }
54
+ </ CellMeasurer >
55
+ ) ;
56
+
57
+ DynamicRow . propTypes = {
58
+ rowIndex : PropTypes . number ,
59
+ parent : PropTypes . any ,
60
+ children : PropTypes . node
61
+ } ;
62
+
63
+
42
64
class ReactSortableTree extends Component {
43
65
constructor ( props ) {
44
66
super ( props ) ;
@@ -78,6 +100,7 @@ class ReactSortableTree extends Component {
78
100
this . startDrag = this . startDrag . bind ( this ) ;
79
101
this . dragHover = this . dragHover . bind ( this ) ;
80
102
this . endDrag = this . endDrag . bind ( this ) ;
103
+ this . handleResize = this . handleResize . bind ( this ) ;
81
104
}
82
105
83
106
componentWillMount ( ) {
@@ -86,6 +109,10 @@ class ReactSortableTree extends Component {
86
109
this . ignoreOneTreeUpdate = false ;
87
110
}
88
111
112
+ componentWillUnmount ( ) {
113
+ cellMeasurerCache . clearAll ( ) ;
114
+ }
115
+
89
116
toggleChildrenVisibility ( { node : targetNode , path, treeIndex : _treeIndex } ) {
90
117
const treeData = changeNodeAtPath ( {
91
118
treeData : this . props . treeData ,
@@ -121,6 +148,8 @@ class ReactSortableTree extends Component {
121
148
122
149
this . props . onChange ( treeData ) ;
123
150
151
+ this . handleResize ( ) ;
152
+
124
153
if ( this . props . onMoveNode ) {
125
154
this . props . onMoveNode ( { treeData, node, treeIndex, path } ) ;
126
155
}
@@ -317,6 +346,15 @@ class ReactSortableTree extends Component {
317
346
} ) ;
318
347
}
319
348
349
+ handleResize ( ) {
350
+ const { isDynamicHeight } = this . props ;
351
+
352
+ if ( isDynamicHeight && this . _list ) {
353
+ cellMeasurerCache . clearAll ( ) ;
354
+ this . _list . wrappedInstance . recomputeRowHeights ( ) ;
355
+ }
356
+ }
357
+
320
358
render ( ) {
321
359
const {
322
360
style,
@@ -325,6 +363,7 @@ class ReactSortableTree extends Component {
325
363
rowHeight,
326
364
getNodeKey,
327
365
isVirtualized,
366
+ isDynamicHeight,
328
367
} = this . props ;
329
368
const {
330
369
rows,
@@ -347,9 +386,12 @@ class ReactSortableTree extends Component {
347
386
const ScrollZoneVirtualList = this . scrollZoneVirtualList ;
348
387
// Render list with react-virtualized
349
388
list = (
350
- < AutoSizer >
389
+ < AutoSizer onResize = { this . handleResize } >
351
390
{ ( { height, width} ) => (
352
391
< ScrollZoneVirtualList
392
+ ref = { ( ref ) => {
393
+ this . _list = ref ;
394
+ } }
353
395
{ ...scrollToInfo }
354
396
verticalStrength = { this . vStrength }
355
397
horizontalStrength = { this . hStrength }
@@ -362,14 +404,16 @@ class ReactSortableTree extends Component {
362
404
style = { innerStyle }
363
405
rowCount = { rows . length }
364
406
estimatedRowSize = { typeof rowHeight !== 'function' ? rowHeight : undefined }
365
- rowHeight = { rowHeight }
366
- rowRenderer = { ( { index, key, style : rowStyle } ) => this . renderRow (
407
+ deferredMeasurementCache = { isDynamicHeight ? cellMeasurerCache : undefined }
408
+ rowHeight = { isDynamicHeight ? cellMeasurerCache . rowHeight : rowHeight }
409
+ rowRenderer = { ( { index, key, style : rowStyle , parent } ) => this . renderRow (
367
410
rows [ index ] ,
368
411
index ,
369
412
key ,
370
413
rowStyle ,
371
414
( ) => ( rows [ index - 1 ] || null ) ,
372
- matchKeys
415
+ matchKeys ,
416
+ parent
373
417
) }
374
418
{ ...this . props . reactVirtualizedListProps }
375
419
/>
@@ -407,7 +451,8 @@ class ReactSortableTree extends Component {
407
451
key ,
408
452
style ,
409
453
getPrevRow ,
410
- matchKeys
454
+ matchKeys ,
455
+ parent
411
456
) {
412
457
const TreeNodeRenderer = this . treeNodeRenderer ;
413
458
const NodeContentRenderer = this . nodeContentRenderer ;
@@ -426,6 +471,34 @@ class ReactSortableTree extends Component {
426
471
isSearchFocus,
427
472
} ) ;
428
473
474
+ const content = (
475
+ < NodeContentRenderer
476
+ node = { node }
477
+ parentNode = { parentNode }
478
+ path = { path }
479
+ isSearchMatch = { isSearchMatch }
480
+ isSearchFocus = { isSearchFocus }
481
+ treeIndex = { treeIndex }
482
+ startDrag = { this . startDrag }
483
+ endDrag = { this . endDrag }
484
+ toggleChildrenVisibility = { this . toggleChildrenVisibility }
485
+ scaffoldBlockPxWidth = { this . props . scaffoldBlockPxWidth }
486
+ onHeightChange = { ( ) => cellMeasurerCache . clear ( treeIndex , 0 ) }
487
+ { ...nodeProps }
488
+ />
489
+ ) ;
490
+
491
+ let row ;
492
+ if ( this . props . isDynamicHeight ) {
493
+ row = (
494
+ < DynamicRow parent = { parent } rowIndex = { listIndex } >
495
+ { content }
496
+ </ DynamicRow >
497
+ ) ;
498
+ } else {
499
+ row = content ;
500
+ }
501
+
429
502
return (
430
503
< TreeNodeRenderer
431
504
style = { style }
@@ -446,19 +519,7 @@ class ReactSortableTree extends Component {
446
519
maxDepth = { this . props . maxDepth }
447
520
dragHover = { this . dragHover }
448
521
>
449
- < NodeContentRenderer
450
- node = { node }
451
- parentNode = { parentNode }
452
- path = { path }
453
- isSearchMatch = { isSearchMatch }
454
- isSearchFocus = { isSearchFocus }
455
- treeIndex = { treeIndex }
456
- startDrag = { this . startDrag }
457
- endDrag = { this . endDrag }
458
- toggleChildrenVisibility = { this . toggleChildrenVisibility }
459
- scaffoldBlockPxWidth = { this . props . scaffoldBlockPxWidth }
460
- { ...nodeProps }
461
- />
522
+ { row }
462
523
</ TreeNodeRenderer >
463
524
) ;
464
525
}
@@ -525,6 +586,10 @@ ReactSortableTree.propTypes = {
525
586
// NOTE: Auto-scrolling while dragging, and scrolling to the `searchFocusOffset` will be disabled.
526
587
isVirtualized : PropTypes . bool ,
527
588
589
+ // Set to false to disable CellMeasurer.
590
+ // NOTE: rowHeight will be ignored.
591
+ isDynamicHeight : PropTypes . bool ,
592
+
528
593
// Override the default component for rendering nodes (but keep the scaffolding generator)
529
594
// This is an advanced option for complete customization of the appearance.
530
595
// It is best to copy the component in `node-renderer-default.js` to use as a base, and customize as needed.
0 commit comments