Skip to content

Commit 7cb456c

Browse files
committed
Implement onMouseOut prop
1 parent 5d6804b commit 7cb456c

File tree

5 files changed

+209
-125
lines changed

5 files changed

+209
-125
lines changed

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,9 @@ class MyComponent extends React.Component {
8484
|:------------------------|:-----------------------|:------------------------------------------------------------------------------|:----------|:--------------------------------------------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
8585
| `data` | `array` | | required | `undefined` | Single-element array containing hierarchical object (see `myTreeData` above). <br /> Contains (at least) `name` and `parent` keys. |
8686
| `nodeSvgShape` | `object` | see [Node shapes](#node-shapes) | | `{shape: 'circle', shapeProps: r: 10}` | Sets a specific SVG shape element + shapeProps to be used for each node. |
87-
| `onClick` | `func` | | | `undefined` | Callback function to be called whenever a node is clicked. <br /><br /> The clicked node's data object is passed to the callback function. |
88-
| `onMouseOver` | `func` | | | `undefined` | Callback function to be called whenever a node is clicked. <br /><br /> The clicked node's data object is passed to the callback |
87+
| `onClick` | `func` | | | `undefined` | Callback function to be called when a node is clicked. <br /><br /> The clicked node's data object is passed to the callback function. |
88+
| `onMouseOver` | `func` | | | `undefined` | Callback function to be called when mouse enters the space belonging to a node. <br /><br /> The node's data object is passed to the callback. |
89+
| `onMouseOut` | `func` | | | `undefined` | Callback function to be called when mouse leaves the space belonging to a node. <br /><br /> The node's data object is passed to the callback. |
8990
| `orientation` | `string` (enum) | `horizontal` `vertical` | | `horizontal` | `horizontal` - Tree expands left-to-right. <br /><br /> `vertical` - Tree expands top-to-bottom. |
9091
| `translate` | `object` | | | `{x: 0, y: 0}` | Translates the graph along the x/y axis by the specified amount of pixels (avoids the graph being stuck in the top left canvas corner). |
9192
| `pathFunc` | `string (enum)`/`func` | `diagonal`<br/>`elbow`<br/>`straight`<br/>`customFunc(linkData, orientation)` | | `diagonal` | `diagonal` - Smooth, curved edges between parent-child nodes. <br /><br /> `elbow` - Sharp edges at right angles between parent-child nodes. <br /><br /> `straight` - Straight lines between parent-child nodes. <br /><br /> `customFunc` - Custom draw function that accepts `linkData` as its first param and `orientation` as its second. |

src/Node/index.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export default class Node extends React.Component {
2121

2222
this.handleClick = this.handleClick.bind(this);
2323
this.handleOnMouseOver = this.handleOnMouseOver.bind(this);
24+
this.handleOnMouseOut = this.handleOnMouseOut.bind(this);
2425
}
2526

2627
componentDidMount() {
@@ -80,6 +81,10 @@ export default class Node extends React.Component {
8081
this.props.onMouseOver(this.props.nodeData.id);
8182
}
8283

84+
handleOnMouseOut() {
85+
this.props.onMouseOut(this.props.nodeData.id);
86+
}
87+
8388
componentWillLeave(done) {
8489
const { nodeData: { parent }, orientation, transitionDuration } = this.props;
8590
const originX = parent ? parent.x : 0;
@@ -103,7 +108,7 @@ export default class Node extends React.Component {
103108
transform={this.state.transform}
104109
onClick={this.handleClick}
105110
onMouseOver={this.handleOnMouseOver}
106-
onFocus={this.handleOnMouseOver}
111+
onMouseOut={this.handleOnMouseOut}
107112
>
108113
{/* TODO: DEPRECATE <circle /> */}
109114
{this.props.circleRadius ? (
@@ -171,6 +176,7 @@ Node.propTypes = {
171176
transitionDuration: PropTypes.number.isRequired,
172177
onClick: PropTypes.func.isRequired,
173178
onMouseOver: PropTypes.func.isRequired,
179+
onMouseOut: PropTypes.func.isRequired,
174180
name: PropTypes.string.isRequired,
175181
attributes: PropTypes.object,
176182
textLayout: PropTypes.object.isRequired,

src/Node/tests/index.test.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ describe('<Node />', () => {
3333
transitionDuration: 500,
3434
onClick: () => {},
3535
onMouseOver: () => {},
36+
onMouseOut: () => {},
3637
textLayout: {
3738
textAnchor: 'start',
3839
x: 10,
@@ -146,6 +147,15 @@ describe('<Node />', () => {
146147
expect(onMouseOverSpy).toHaveBeenCalledWith(nodeData.id);
147148
});
148149

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+
149159
it('maps each `props.attributes` to a <tspan> element', () => {
150160
const fixture = { keyA: 'valA', keyB: 'valB' };
151161
const renderedComponent = shallow(<Node {...mockProps} attributes={fixture} />);

src/Tree/index.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export default class Tree extends React.Component {
2222
this.handleNodeToggle = this.handleNodeToggle.bind(this);
2323
this.handleOnClickCb = this.handleOnClickCb.bind(this);
2424
this.handleOnMouseOverCb = this.handleOnMouseOverCb.bind(this);
25+
this.handleOnMouseOutCb = this.handleOnMouseOutCb.bind(this);
2526
}
2627

2728
componentDidMount() {
@@ -221,6 +222,23 @@ export default class Tree extends React.Component {
221222
}
222223
}
223224

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+
224242
/**
225243
* generateTree - Generates tree elements (`nodes` and `links`) by
226244
* grabbing the rootNode from `this.state.data[0]`.
@@ -308,6 +326,7 @@ export default class Tree extends React.Component {
308326
attributes={nodeData.attributes}
309327
onClick={this.handleNodeToggle}
310328
onMouseOver={this.handleOnMouseOverCb}
329+
onMouseOut={this.handleOnMouseOutCb}
311330
textLayout={textLayout}
312331
circleRadius={circleRadius}
313332
subscriptions={subscriptions}
@@ -330,6 +349,7 @@ Tree.defaultProps = {
330349
},
331350
onClick: undefined,
332351
onMouseOver: undefined,
352+
onMouseOut: undefined,
333353
orientation: 'horizontal',
334354
translate: { x: 0, y: 0 },
335355
pathFunc: 'diagonal',
@@ -359,6 +379,7 @@ Tree.propTypes = {
359379
}),
360380
onClick: PropTypes.func,
361381
onMouseOver: PropTypes.func,
382+
onMouseOut: PropTypes.func,
362383
orientation: PropTypes.oneOf(['horizontal', 'vertical']),
363384
translate: PropTypes.shape({
364385
x: PropTypes.number,

0 commit comments

Comments
 (0)