Skip to content

Commit 42ddf3e

Browse files
committed
JSK-11518: storybook: reproduce "rowHeight not refreshing while dragging" frontend-collective#264
1 parent 4a0c07e commit 42ddf3e

File tree

2 files changed

+224
-1
lines changed

2 files changed

+224
-1
lines changed

stories/index.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import ThemesExample from './themes';
2020
import TouchSupportExample from './touch-support';
2121
import TreeDataIOExample from './tree-data-io';
2222
import TreeToTreeExample from './tree-to-tree';
23+
import RowHeight from "./row-height";
2324

2425
storiesOf('Basics', module)
2526
.add('Minimal implementation', () => <BarebonesExample />)
@@ -42,4 +43,6 @@ storiesOf('Advanced', module)
4243
.add('Prevent some nodes from having children', () => <ChildlessNodes />)
4344
.add('Minimal implementation without Dnd Context', () => (
4445
<BarebonesExampleNoContext />
45-
));
46+
))
47+
.add('Row height function', () => <RowHeight isVirtualized={false} />)
48+
.add('Row height function + react-virtualized', () => <RowHeight isVirtualized />);

stories/row-height.js

+220
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
/* eslint-disable react/no-multi-comp */
2+
import PropTypes from 'prop-types';
3+
import React, { Component } from 'react';
4+
import { DndProvider, DragSource } from 'react-dnd';
5+
import { HTML5Backend } from 'react-dnd-html5-backend';
6+
import { SortableTreeWithoutDndContext as SortableTree } from '../src';
7+
// In your own app, you would need to use import styles once in the app
8+
// import 'react-sortable-tree/styles.css';
9+
10+
// -------------------------
11+
// Create an drag source component that can be dragged into the tree
12+
// https://react-dnd.github.io/react-dnd/docs-drag-source.html
13+
// -------------------------
14+
// This type must be assigned to the tree via the `dndType` prop as well
15+
const externalNodeType = 'yourNodeType';
16+
const externalNodeSpec = {
17+
// This needs to return an object with a property `node` in it.
18+
// Object rest spread is recommended to avoid side effects of
19+
// referencing the same object in different trees.
20+
beginDrag: componentProps => ({ node: { ...componentProps.node } }),
21+
};
22+
const externalNodeCollect = (connect /* , monitor */) => ({
23+
connectDragSource: connect.dragSource(),
24+
// Add props via react-dnd APIs to enable more visual
25+
// customization of your component
26+
// isDragging: monitor.isDragging(),
27+
// didDrop: monitor.didDrop(),
28+
});
29+
class externalNodeBaseComponent extends Component {
30+
render() {
31+
const { connectDragSource, node } = this.props;
32+
33+
return connectDragSource(
34+
<div
35+
style={{
36+
display: 'inline-block',
37+
padding: '3px 5px',
38+
background: 'blue',
39+
color: 'white',
40+
}}
41+
>
42+
{node.title}
43+
</div>,
44+
{ dropEffect: 'copy' }
45+
);
46+
}
47+
}
48+
externalNodeBaseComponent.propTypes = {
49+
node: PropTypes.shape({ title: PropTypes.string }).isRequired,
50+
connectDragSource: PropTypes.func.isRequired,
51+
};
52+
const YourExternalNodeComponent = DragSource(
53+
externalNodeType,
54+
externalNodeSpec,
55+
externalNodeCollect
56+
)(externalNodeBaseComponent);
57+
58+
function canDrop(args) {
59+
console.log('canDrop:', args);
60+
61+
const { node, nextParent } = args;
62+
63+
if (node.isPerson) {
64+
return nextParent && !nextParent.isPerson;
65+
}
66+
return true;
67+
}
68+
69+
class App extends Component {
70+
constructor(props) {
71+
super(props);
72+
73+
this.state = {
74+
treeData: [
75+
{
76+
title: 'Managers',
77+
id: 1000,
78+
expanded: true,
79+
children: [
80+
{
81+
id: 1,
82+
title: 'Rob',
83+
children: [],
84+
isPerson: true,
85+
},
86+
{
87+
id: 2,
88+
title: 'Joe',
89+
children: [],
90+
isPerson: true,
91+
},
92+
],
93+
},
94+
{
95+
title: 'Clerks',
96+
id: 2000,
97+
expanded: true,
98+
children: [
99+
{
100+
id: 3,
101+
title: 'Bertha',
102+
children: [],
103+
isPerson: true,
104+
},
105+
{
106+
id: 4,
107+
title: 'Billy',
108+
children: [],
109+
isPerson: true,
110+
},
111+
],
112+
},
113+
],
114+
};
115+
116+
this.draggedNode = null;
117+
118+
this.onDragStateChanged = this.onDragStateChanged.bind(this);
119+
this.calcRowHeight = this.calcRowHeight.bind(this);
120+
this.onChange= this.onChange.bind(this);
121+
this.virtualListRecomputeRowHeights = this.virtualListRecomputeRowHeights.bind(this);
122+
123+
this.refReactVirtualizedList = React.createRef();
124+
125+
this.reactVirtualizedListProps = {
126+
// autoHeight: true,
127+
ref: this.refReactVirtualizedList,
128+
}
129+
130+
this.recomputingRowHeight = false;
131+
}
132+
133+
onDragStateChanged(args) {
134+
console.log('onDragStateChanged:', args);
135+
136+
const { draggedNode } = args;
137+
const { isVirtualized } = this.props;
138+
this.draggedNode = draggedNode;
139+
140+
const app = this;
141+
142+
if (!draggedNode && !isVirtualized) {
143+
setTimeout(
144+
() => {
145+
app.setState((state) => {
146+
console.log('state:', state);
147+
return ({
148+
treeData: [...state.treeData]
149+
});
150+
});
151+
},
152+
10
153+
);
154+
}
155+
156+
if (draggedNode) {
157+
this.dragInterval = setInterval(this.virtualListRecomputeRowHeights, 250);
158+
} else {
159+
clearInterval(this.dragInterval);
160+
this.virtualListRecomputeRowHeights();
161+
}
162+
163+
// this.virtualListRecomputeRowHeights();
164+
}
165+
166+
calcRowHeight(args) {
167+
console.log('calcRowHeight:', args);
168+
169+
if (args.node === this.draggedNode) {
170+
return 10;
171+
}
172+
173+
return 62;
174+
}
175+
176+
onChange(newTreeData) {
177+
this.setState({treeData: newTreeData});
178+
}
179+
180+
virtualListRecomputeRowHeights() {
181+
if (this.props.isVirtualized && !this.recomputingRowHeight) {
182+
this.recomputingRowHeight = true;
183+
console.log('calling recomputeRowHeights()');
184+
// TODO seems like calling recomputeRowHeights() aborts dragging :c
185+
this.refReactVirtualizedList.current.wrappedInstance.current.recomputeRowHeights();
186+
this.recomputingRowHeight = false;
187+
}
188+
}
189+
190+
render() {
191+
console.log('render');
192+
193+
return (
194+
<DndProvider backend={HTML5Backend}>
195+
<div>
196+
<div style={{ height: 500 }}>
197+
<SortableTree
198+
canDrop={canDrop}
199+
dndType={externalNodeType}
200+
isVirtualized={this.props.isVirtualized}
201+
onDragStateChanged={this.onDragStateChanged}
202+
reactVirtualizedListProps={this.reactVirtualizedListProps}
203+
rowHeight={this.calcRowHeight}
204+
onChange={this.onChange}
205+
treeData={this.state.treeData}
206+
/>
207+
</div>
208+
<YourExternalNodeComponent node={{ title: 'New worker', isPerson: true, }} />← drag
209+
this
210+
</div>
211+
</DndProvider>
212+
);
213+
}
214+
}
215+
216+
App.propTypes = {
217+
isVirtualized: PropTypes.bool.isRequired,
218+
}
219+
220+
export default App;

0 commit comments

Comments
 (0)