Skip to content

Commit 085287a

Browse files
committed
Get basic tree structure and appearance working
1 parent bba0463 commit 085287a

18 files changed

+640
-98
lines changed

Diff for: .eslintrc.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"jasmine": true
77
},
88
"rules": {
9-
"react/jsx-filename-extension": 0
9+
"react/jsx-filename-extension": 0,
10+
"react/prefer-stateless-function": 0
1011
}
1112
}

Diff for: README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
### Features
66

7-
- Highly flexible
7+
- Works right out of the box, but is highly customizable
88
- No external CSS files
99

1010
## Example

Diff for: package.json

+13-9
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@
33
"version": "0.0.1",
44
"description": "Drag-and-drop sortable representation of hierarchical data",
55
"scripts": {
6-
"build": "npm run lint && npm run build:demo && npm run build:umd",
6+
"build": "npm run lint && npm run test && npm run build:demo && npm run build:umd",
77
"build:demo": "npm run clean:demo && cross-env NODE_ENV=production webpack --config webpack.config.demo.babel.js --bail",
88
"build:umd": "npm run clean:umd && cross-env NODE_ENV=production webpack --config webpack.config.umd.babel.js --bail",
99
"clean": "npm run clean:demo && npm run clean:umd",
1010
"clean:demo": "rimraf build",
1111
"clean:umd": "rimraf dist/umd",
1212
"start": "cross-env NODE_ENV=development webpack-dev-server --hot --inline --config webpack.config.dev.babel.js",
1313
"lint": "eslint src",
14-
"prepublish": "npm run test && npm run build:umd",
14+
"prepublish": "npm run lint && npm run test && npm run build:umd",
1515
"posttest": "[ -z \"$CI\" ] || codecov",
1616
"test": "cross-env NODE_ENV=test karma start --single-run",
1717
"test:watch": "cross-env NODE_ENV=test karma start",
@@ -31,10 +31,15 @@
3131
"Chris Fritz"
3232
],
3333
"license": "MIT",
34-
"dependencies": {},
34+
"dependencies": {
35+
"react-dnd": "^2.1.4",
36+
"react-dnd-html5-backend": "^2.1.2",
37+
"react-virtualized": "^7.17.0"
38+
},
3539
"peerDependencies": {
36-
"react": "^15.0.0",
37-
"react-dom": "^15.0.0"
40+
"react": "^15.3.0",
41+
"react-addons-shallow-compare": "^15.3.0",
42+
"react-dom": "^15.3.0"
3843
},
3944
"devDependencies": {
4045
"autoprefixer": "^6.3.7",
@@ -45,7 +50,6 @@
4550
"babel-plugin-transform-object-rest-spread": "^6.8.0",
4651
"babel-preset-es2015": "^6.9.0",
4752
"babel-preset-react": "^6.11.1",
48-
"bluebird": "^3.4.1",
4953
"cross-env": "^2.0.0",
5054
"css-loader": "^0.23.1",
5155
"eslint": "^3.2.2",
@@ -69,13 +73,13 @@
6973
"karma-webpack": "^1.7.0",
7074
"node-sass": "^3.8.0",
7175
"postcss-loader": "^0.9.1",
72-
"react": "^15.2.0",
73-
"react-dom": "^15.2.0",
76+
"react": "^15.3.0",
77+
"react-addons-shallow-compare": "^15.3.0",
78+
"react-dom": "^15.3.0",
7479
"react-hot-loader": "^1.3.0",
7580
"rimraf": "^2.5.3",
7681
"sass-loader": "^4.0.0",
7782
"style-loader": "^0.13.1",
78-
"watch": "^0.19.1",
7983
"webpack": "^1.13.1",
8084
"webpack-dev-server": "^1.14.1"
8185
},

Diff for: src/examples/basicExample/app.js

+77-2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,68 @@ const App = React.createClass({
1313
const authorUrl = 'https://github.com/fritz-c';
1414
const githubUrl = 'https://github.com/fritz-c/react-sortable-tree';
1515

16+
const treeData = [
17+
{
18+
key: 'b12314', // string or number. Every key in the tree needs to be unique
19+
value: { // Custom value. Can be anything - object, array, string, etc.
20+
id: 'b12314',
21+
title: 'Joe',
22+
subtitle: 'Pancakes',
23+
},
24+
expanded: true,
25+
children: [
26+
{
27+
value: 1,
28+
children: [], // null or undefined also ok
29+
},
30+
{
31+
value: 2,
32+
},
33+
{
34+
key: 2412,
35+
value: 2,
36+
children: (resolve, _reject) => {
37+
setTimeout(() => {
38+
resolve([
39+
{
40+
key: 1215,
41+
value: 5,
42+
},
43+
{
44+
key: 2125,
45+
value: 215,
46+
},
47+
]);
48+
}, 2000);
49+
},
50+
},
51+
],
52+
},
53+
{
54+
key: 'b12315',
55+
value: {
56+
id: 'b12315',
57+
title: 'Frank',
58+
},
59+
},
60+
{
61+
key: 'b12316',
62+
value: {
63+
id: 'b12316',
64+
title: 'Beast Man',
65+
subtitle: 'Pancakes',
66+
},
67+
},
68+
{
69+
key: 'b12336',
70+
value: {
71+
id: 'b12336',
72+
title: 'Tracy Page',
73+
subtitle: 'Waffles',
74+
},
75+
},
76+
];
77+
1678
return (
1779
<div>
1880
<section className={styles['page-header']}>
@@ -26,11 +88,24 @@ const App = React.createClass({
2688
<section className={styles['main-content']}>
2789
<h3>Demo</h3>
2890

29-
<SortableTree myName={authorName} />
91+
<SortableTree
92+
treeData={treeData}
93+
generateNodeProps={({
94+
nodeData: _nodeData,
95+
parentPath: _parentPath,
96+
lowerSiblingCounts: _lowerSiblingCounts,
97+
listIndex: _listIndex,
98+
}) => ({
99+
buttons: [
100+
<button></button>,
101+
<button></button>,
102+
],
103+
})}
104+
/>
30105

31106
<h3>Features</h3>
32107
<ul>
33-
<li>Excels at displaying an enthusiastic greeting</li>
108+
<li>Works right out of the box, but is highly customizable</li>
34109
<li>No external CSS</li>
35110
</ul>
36111

Diff for: src/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
import SortableTree from './react-sortable-tree';
2+
23
export * from './utils/tree-data-utils';
34
export default SortableTree;

Diff for: src/item-types.js

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default {
2+
HANDLE: 'HANDLE',
3+
};

Diff for: src/node-renderer-default.js

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import React, { PropTypes } from 'react';
2+
import styles from './node-renderer-default.scss';
3+
4+
const NodeRendererDefault = ({
5+
scaffoldBlockPxWidth,
6+
toggleChildrenVisibility,
7+
connectDragPreview,
8+
connectDragSource,
9+
isDragging,
10+
nodeData,
11+
buttons,
12+
}) => (
13+
<div style={{ height: '100%' }}>
14+
{toggleChildrenVisibility && nodeData.children && nodeData.children.length > 0 && (
15+
<div
16+
className={nodeData.expanded ? styles.collapseButton : styles.expandButton}
17+
style={{ left: -0.5 * scaffoldBlockPxWidth }}
18+
onClick={toggleChildrenVisibility}
19+
/>
20+
)}
21+
22+
{/* Set the row preview to be used during drag and drop */}
23+
{connectDragPreview(
24+
<div className={styles.row + (isDragging ? ` ${styles.rowOriginWhileDragging}` : '')}>
25+
{connectDragSource(( // Sets this handle as the element to start a drag-and-drop
26+
<div
27+
className={`${styles.rowItem} ${styles.moveHandle}`}
28+
/>
29+
), { dropEffect: 'copy' })}
30+
31+
<div className={styles.rowContents}>
32+
<div className={styles.rowLabel}>
33+
<span
34+
className={styles.rowTitle +
35+
(nodeData.value.subtitle ? ` ${styles.rowTitleWithSubtitle}` : '')
36+
}
37+
>
38+
{nodeData.value.title}
39+
</span>
40+
41+
{nodeData.value.subtitle &&
42+
<span className={styles.rowSubtitle}>
43+
{nodeData.value.subtitle}
44+
</span>
45+
}
46+
</div>
47+
48+
<div className={styles.rowToolbar}>
49+
{buttons && buttons.map((btn, index) => (
50+
<div key={index} className={styles.rowItem}>
51+
{btn}
52+
</div>
53+
))}
54+
</div>
55+
</div>
56+
</div>
57+
)}
58+
</div>
59+
);
60+
61+
NodeRendererDefault.propTypes = {
62+
nodeData: PropTypes.object.isRequired,
63+
parentPath: PropTypes.arrayOf(PropTypes.oneOfType([ PropTypes.string, PropTypes.number ])).isRequired,
64+
lowerSiblingCounts: PropTypes.arrayOf(PropTypes.number).isRequired,
65+
66+
scaffoldBlockPxWidth: PropTypes.number.isRequired,
67+
toggleChildrenVisibility: PropTypes.func,
68+
buttons: PropTypes.object.isRequired,
69+
70+
// Drag and drop API functions
71+
connectDragPreview: PropTypes.func.isRequired,
72+
connectDragSource: PropTypes.func.isRequired,
73+
isDragging: PropTypes.bool.isRequired,
74+
};
75+
76+
export default NodeRendererDefault;

Diff for: src/node-renderer-default.scss

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
.fixVertAlign {
2+
&::before {
3+
content: '';
4+
display: inline-block;
5+
vertical-align: middle;
6+
height: 100%;
7+
}
8+
}
9+
10+
.row {
11+
@extend .fixVertAlign;
12+
13+
padding: 10px 10px 10px 0;
14+
height: 100%;
15+
white-space: nowrap;
16+
}
17+
18+
.rowOriginWhileDragging {
19+
opacity: 0.5;
20+
}
21+
22+
.rowContents {
23+
@extend .fixVertAlign;
24+
25+
display: inline-block;
26+
height: 100%;
27+
border: solid #BBB 1px;
28+
border-left: none;
29+
box-shadow: 0 2px 2px -2px;
30+
padding: 0 15px 0 10px;
31+
border-radius: 2px;
32+
min-width: 230px;
33+
34+
&::after {
35+
content: '';
36+
display: inline-block;
37+
width: 100%;
38+
}
39+
}
40+
41+
.rowItem {
42+
display: inline-block;
43+
vertical-align: middle;
44+
max-height: 100%;
45+
overflow: hidden;
46+
}
47+
48+
.moveHandle {
49+
height: 100%;
50+
width: 44px;
51+
background: #D8D8D8 url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MiIgaGVpZ2h0PSI0MiI+PGcgc3Ryb2tlPSIjRkZGIiBzdHJva2Utd2lkdGg9IjIuOSIgPjxwYXRoIGQ9Ik0xNCAxNS43aDE0LjQiLz48cGF0aCBkPSJNMTQgMjEuNGgxNC40Ii8+PHBhdGggZD0iTTE0IDI3LjFoMTQuNCIvPjwvZz4KPC9zdmc+') no-repeat center;
52+
border: solid #AAA 1px;
53+
box-shadow: 0 2px 2px -2px;
54+
cursor: move;
55+
border-radius: 1px;
56+
}
57+
58+
.rowLabel {
59+
@extend .rowItem;
60+
padding-right: 20px;
61+
text-align: left;
62+
width: 50%;
63+
line-height: 1;
64+
}
65+
66+
.rowTitle {
67+
font-weight: bold;
68+
}
69+
70+
.rowTitleWithSubtitle {
71+
font-size: 85%;
72+
display: block;
73+
}
74+
75+
.rowSubtitle {
76+
font-size: 70%;
77+
}
78+
79+
.rowToolbar {
80+
@extend .rowItem;
81+
text-align: right;
82+
width: 50%;
83+
}
84+
85+
.visibilityToggleButton {
86+
position: absolute;
87+
border-radius: 100%;
88+
box-shadow: 0 0 0 1px #000;
89+
width: 16px;
90+
height: 16px;
91+
top: 50%;
92+
transform: translateY(-50%) translateX(-50%);
93+
cursor: pointer;
94+
}
95+
96+
.collapseButton {
97+
@extend .visibilityToggleButton;
98+
background: #FFF url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxOCIgaGVpZ2h0PSIxOCI+PGNpcmNsZSBjeD0iOSIgY3k9IjkiIHI9IjgiIGZpbGw9IiNGRkYiLz48ZyBzdHJva2U9IiM5ODk4OTgiIHN0cm9rZS13aWR0aD0iMS45IiA+PHBhdGggZD0iTTQuNSA5aDkiLz48L2c+Cjwvc3ZnPg==') no-repeat center;
99+
}
100+
101+
.expandButton {
102+
@extend .visibilityToggleButton;
103+
background: #FFF url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxOCIgaGVpZ2h0PSIxOCI+PGNpcmNsZSBjeD0iOSIgY3k9IjkiIHI9IjgiIGZpbGw9IiNGRkYiLz48ZyBzdHJva2U9IiM5ODk4OTgiIHN0cm9rZS13aWR0aD0iMS45IiA+PHBhdGggZD0iTTQuNSA5aDkiLz48cGF0aCBkPSJNOSA0LjV2OSIvPjwvZz4KPC9zdmc+') no-repeat center;
104+
}

0 commit comments

Comments
 (0)