Skip to content

Commit ea31f5c

Browse files
committed
Merge branch 'develop'
2 parents 264b218 + 7cb456c commit ea31f5c

File tree

11 files changed

+474
-236
lines changed

11 files changed

+474
-236
lines changed

.eslintrc.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ module.exports = {
5252
"jsx-a11y/heading-has-content": 0,
5353
"jsx-a11y/href-no-hash": 2,
5454
"jsx-a11y/label-has-for": 2,
55-
"jsx-a11y/mouse-events-have-key-events": 2,
55+
"jsx-a11y/mouse-events-have-key-events": 0,
5656
"jsx-a11y/role-has-required-aria-props": 2,
5757
"jsx-a11y/role-supports-aria-props": 2,
5858
"max-len": 0,

.travis.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@ notifications:
1717

1818
after_success: 'npm run coveralls'
1919

20-
cache:
21-
directories:
22-
- node_modules
20+
#cache:
21+
# directories:
22+
# - node_modules

README.md

Lines changed: 21 additions & 19 deletions
Large diffs are not rendered by default.

jest/polyfills/raf.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// eslint-disable-next-line
2+
const raf = global.requestAnimationFrame = cb => {
3+
setTimeout(cb, 0)
4+
}
5+
6+
export default raf

jest/setup.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/* eslint-disable */
2+
import raf from './polyfills/raf'
3+
import { configure } from 'enzyme';
4+
import Adapter from 'enzyme-adapter-react-16';
5+
6+
configure({ adapter: new Adapter() });

package.json

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"precommit": "lint-staged",
99
"build": "yarn clean:lib && webpack --progress --colors --env build",
1010
"dev": "yarn clean:lib && webpack --progress --colors --watch --env dev",
11-
"lint": "eslint .",
11+
"lint": "eslint src/**/*.js",
1212
"test": "yarn lint && jest --coverage --verbose",
1313
"test:clean": "rimraf ./coverage",
1414
"test:watch": "jest --watchAll",
@@ -46,6 +46,7 @@
4646
"lines": 94
4747
}
4848
},
49+
"setupTestFrameworkScriptFile": "<rootDir>/jest/setup.js",
4950
"moduleNameMapper": {
5051
".*\\.(css|less|styl|scss|sass)$": "<rootDir>/jest/mocks/cssModule.js",
5152
".*\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/jest/mocks/image.js"
@@ -59,6 +60,9 @@
5960
"react-transition-group": "^1.1.3",
6061
"uuid": "^3.0.1"
6162
},
63+
"peerDependencies": {
64+
"react": "^15.0.0 || ^16.0.0"
65+
},
6266
"devDependencies": {
6367
"babel-cli": "6.24.1",
6468
"babel-core": "6.24.1",
@@ -71,7 +75,8 @@
7175
"babel-preset-stage-0": "^6.5.0",
7276
"coveralls": "^2.13.1",
7377
"css-loader": "^0.28.1",
74-
"enzyme": "^2.8.2",
78+
"enzyme": "^3.2.0",
79+
"enzyme-adapter-react-16": "^1.1.0",
7580
"eslint": "3.19.0",
7681
"eslint-config-airbnb": "^14.1.0",
7782
"eslint-config-prettier": "^2.5.0",
@@ -86,10 +91,10 @@
8691
"np": "^2.16.0",
8792
"postcss-loader": "^1.3.3",
8893
"prettier": "^1.6.1",
89-
"react": "^15.6.0",
94+
"react": "^16.1.1",
9095
"react-docgen": "^2.16.0",
91-
"react-dom": "^15.6.0",
92-
"react-test-renderer": "^15.5.4",
96+
"react-dom": "^16.1.1",
97+
"react-test-renderer": "^16.1.1",
9398
"regenerator-runtime": "^0.10.5",
9499
"rimraf": "^2.6.1",
95100
"style-loader": "^0.17.0",

src/Node/index.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ export default class Node extends React.Component {
2020
};
2121

2222
this.handleClick = this.handleClick.bind(this);
23+
this.handleOnMouseOver = this.handleOnMouseOver.bind(this);
24+
this.handleOnMouseOut = this.handleOnMouseOut.bind(this);
2325
}
2426

2527
componentDidMount() {
@@ -75,6 +77,14 @@ export default class Node extends React.Component {
7577
this.props.onClick(this.props.nodeData.id);
7678
}
7779

80+
handleOnMouseOver() {
81+
this.props.onMouseOver(this.props.nodeData.id);
82+
}
83+
84+
handleOnMouseOut() {
85+
this.props.onMouseOut(this.props.nodeData.id);
86+
}
87+
7888
componentWillLeave(done) {
7989
const { nodeData: { parent }, orientation, transitionDuration } = this.props;
8090
const originX = parent ? parent.x : 0;
@@ -97,6 +107,8 @@ export default class Node extends React.Component {
97107
className={nodeData._children ? 'nodeBase' : 'leafNodeBase'}
98108
transform={this.state.transform}
99109
onClick={this.handleClick}
110+
onMouseOver={this.handleOnMouseOver}
111+
onMouseOut={this.handleOnMouseOut}
100112
>
101113
{/* TODO: DEPRECATE <circle /> */}
102114
{this.props.circleRadius ? (
@@ -142,6 +154,7 @@ Node.defaultProps = {
142154
textAnchor: 'start',
143155
attributes: undefined,
144156
circleRadius: undefined,
157+
onMouseOver: undefined,
145158
styles: {
146159
node: {
147160
circle: {},
@@ -162,6 +175,8 @@ Node.propTypes = {
162175
orientation: PropTypes.oneOf(['horizontal', 'vertical']).isRequired,
163176
transitionDuration: PropTypes.number.isRequired,
164177
onClick: PropTypes.func.isRequired,
178+
onMouseOver: PropTypes.func.isRequired,
179+
onMouseOut: PropTypes.func.isRequired,
165180
name: PropTypes.string.isRequired,
166181
attributes: PropTypes.object,
167182
textLayout: PropTypes.object.isRequired,

src/Node/tests/index.test.js

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ describe('<Node />', () => {
3232
orientation: 'horizontal',
3333
transitionDuration: 500,
3434
onClick: () => {},
35+
onMouseOver: () => {},
36+
onMouseOut: () => {},
3537
textLayout: {
3638
textAnchor: 'start',
3739
x: 10,
@@ -127,20 +129,33 @@ describe('<Node />', () => {
127129
expect(verticalComponent.find('g').prop('transform')).toBe(verticalTransform);
128130
});
129131

130-
it('should take an `onClick` prop', () => {
131-
const renderedComponent = shallow(<Node {...mockProps} onClick={() => {}} />);
132-
133-
expect(renderedComponent.prop('onClick')).toBeDefined();
134-
});
135-
136-
it('handles click events and passes its nodeId to onClick handler', () => {
132+
it('handles onClick events and passes its nodeId to onClick handler', () => {
137133
const onClickSpy = jest.fn();
138134
const renderedComponent = shallow(<Node {...mockProps} onClick={onClickSpy} />);
139135

140136
renderedComponent.simulate('click');
137+
expect(onClickSpy).toHaveBeenCalledTimes(1);
141138
expect(onClickSpy).toHaveBeenCalledWith(nodeData.id);
142139
});
143140

141+
it('handles onMouseOver events and passes its nodeId to onMouseOver handler', () => {
142+
const onMouseOverSpy = jest.fn();
143+
const renderedComponent = shallow(<Node {...mockProps} onMouseOver={onMouseOverSpy} />);
144+
145+
renderedComponent.simulate('mouseover');
146+
expect(onMouseOverSpy).toHaveBeenCalledTimes(1);
147+
expect(onMouseOverSpy).toHaveBeenCalledWith(nodeData.id);
148+
});
149+
150+
it('handles onMouseOut events and passes its nodeId to onMouseOut handler', () => {
151+
const onMouseOutSpy = jest.fn();
152+
const renderedComponent = shallow(<Node {...mockProps} onMouseOut={onMouseOutSpy} />);
153+
154+
renderedComponent.simulate('mouseout');
155+
expect(onMouseOutSpy).toHaveBeenCalledTimes(1);
156+
expect(onMouseOutSpy).toHaveBeenCalledWith(nodeData.id);
157+
});
158+
144159
it('maps each `props.attributes` to a <tspan> element', () => {
145160
const fixture = { keyA: 'valA', keyB: 'valB' };
146161
const renderedComponent = shallow(<Node {...mockProps} attributes={fixture} />);

src/Tree/index.js

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ export default class Tree extends React.Component {
2121
this.collapseNode = this.collapseNode.bind(this);
2222
this.handleNodeToggle = this.handleNodeToggle.bind(this);
2323
this.handleOnClickCb = this.handleOnClickCb.bind(this);
24+
this.handleOnMouseOverCb = this.handleOnMouseOverCb.bind(this);
25+
this.handleOnMouseOutCb = this.handleOnMouseOutCb.bind(this);
2426
}
2527

2628
componentDidMount() {
@@ -203,6 +205,40 @@ export default class Tree extends React.Component {
203205
}
204206
}
205207

208+
/**
209+
* handleOnMouseOverCb - Handles the user-defined `onMouseOver` function
210+
*
211+
* @param {string} nodeId
212+
*
213+
* @return {void}
214+
*/
215+
handleOnMouseOverCb(nodeId) {
216+
const { onMouseOver } = this.props;
217+
if (onMouseOver && typeof onMouseOver === 'function') {
218+
const data = clone(this.state.data);
219+
const matches = this.findNodesById(nodeId, data, []);
220+
const targetNode = matches[0];
221+
onMouseOver(clone(targetNode));
222+
}
223+
}
224+
225+
/**
226+
* handleOnMouseOutCb - Handles the user-defined `onMouseOut` function
227+
*
228+
* @param {string} nodeId
229+
*
230+
* @return {void}
231+
*/
232+
handleOnMouseOutCb(nodeId) {
233+
const { onMouseOut } = this.props;
234+
if (onMouseOut && typeof onMouseOut === 'function') {
235+
const data = clone(this.state.data);
236+
const matches = this.findNodesById(nodeId, data, []);
237+
const targetNode = matches[0];
238+
onMouseOut(clone(targetNode));
239+
}
240+
}
241+
206242
/**
207243
* generateTree - Generates tree elements (`nodes` and `links`) by
208244
* grabbing the rootNode from `this.state.data[0]`.
@@ -218,7 +254,7 @@ export default class Tree extends React.Component {
218254
.tree()
219255
.nodeSize(orientation === 'horizontal' ? [nodeSize.y, nodeSize.x] : [nodeSize.x, nodeSize.y])
220256
.separation(
221-
(a, b) => (deepEqual(a.parent, b.parent) ? separation.siblings : separation.nonSiblings),
257+
(a, b) => (a.parent.id === b.parent.id ? separation.siblings : separation.nonSiblings),
222258
)
223259
.children(d => (d._collapsed ? null : d._children));
224260

@@ -289,6 +325,8 @@ export default class Tree extends React.Component {
289325
name={nodeData.name}
290326
attributes={nodeData.attributes}
291327
onClick={this.handleNodeToggle}
328+
onMouseOver={this.handleOnMouseOverCb}
329+
onMouseOut={this.handleOnMouseOutCb}
292330
textLayout={textLayout}
293331
circleRadius={circleRadius}
294332
subscriptions={subscriptions}
@@ -310,6 +348,8 @@ Tree.defaultProps = {
310348
},
311349
},
312350
onClick: undefined,
351+
onMouseOver: undefined,
352+
onMouseOut: undefined,
313353
orientation: 'horizontal',
314354
translate: { x: 0, y: 0 },
315355
pathFunc: 'diagonal',
@@ -338,6 +378,8 @@ Tree.propTypes = {
338378
shapeProps: PropTypes.object,
339379
}),
340380
onClick: PropTypes.func,
381+
onMouseOver: PropTypes.func,
382+
onMouseOut: PropTypes.func,
341383
orientation: PropTypes.oneOf(['horizontal', 'vertical']),
342384
translate: PropTypes.shape({
343385
x: PropTypes.number,

0 commit comments

Comments
 (0)