diff --git a/packages/line/src/Line.js b/packages/line/src/Line.js index 7956479100..613734740f 100644 --- a/packages/line/src/Line.js +++ b/packages/line/src/Line.js @@ -220,6 +220,10 @@ const Line = props => { tooltip={sliceTooltip} current={currentSlice} setCurrent={setCurrentSlice} + onMouseEnter={onMouseEnter} + onMouseMove={onMouseMove} + onMouseLeave={onMouseLeave} + onClick={onClick} /> ) } diff --git a/packages/line/src/Slices.js b/packages/line/src/Slices.js index 952688cfee..a2afd140f2 100644 --- a/packages/line/src/Slices.js +++ b/packages/line/src/Slices.js @@ -10,7 +10,19 @@ import { memo } from 'react' import PropTypes from 'prop-types' import SlicesItem from './SlicesItem' -const Slices = ({ slices, axis, debug, height, tooltip, current, setCurrent }) => { +const Slices = ({ + slices, + axis, + debug, + height, + tooltip, + current, + setCurrent, + onMouseEnter, + onMouseMove, + onMouseLeave, + onClick, +}) => { return slices.map(slice => ( )) } @@ -44,6 +60,10 @@ Slices.propTypes = { tooltip: PropTypes.oneOfType([PropTypes.func, PropTypes.object]).isRequired, current: PropTypes.object, setCurrent: PropTypes.func.isRequired, + onMouseEnter: PropTypes.func, + onMouseMove: PropTypes.func, + onMouseLeave: PropTypes.func, + onClick: PropTypes.func, } export default memo(Slices) diff --git a/packages/line/src/SlicesItem.js b/packages/line/src/SlicesItem.js index fb01ca26c3..d102e9bbf0 100644 --- a/packages/line/src/SlicesItem.js +++ b/packages/line/src/SlicesItem.js @@ -10,28 +10,52 @@ import { createElement, memo, useCallback } from 'react' import PropTypes from 'prop-types' import { useTooltip } from '@nivo/tooltip' -const SlicesItem = ({ slice, axis, debug, tooltip, isCurrent, setCurrent }) => { +const SlicesItem = ({ + slice, + axis, + debug, + tooltip, + isCurrent, + setCurrent, + onMouseEnter, + onMouseMove, + onMouseLeave, + onClick, +}) => { const { showTooltipFromEvent, hideTooltip } = useTooltip() const handleMouseEnter = useCallback( event => { showTooltipFromEvent(createElement(tooltip, { slice, axis }), event, 'right') setCurrent(slice) + onMouseEnter && onMouseEnter(slice, event) }, - [showTooltipFromEvent, tooltip, slice] + [showTooltipFromEvent, tooltip, slice, onMouseEnter] ) const handleMouseMove = useCallback( event => { showTooltipFromEvent(createElement(tooltip, { slice, axis }), event, 'right') + onMouseMove && onMouseMove(slice, event) }, - [showTooltipFromEvent, tooltip, slice] + [showTooltipFromEvent, tooltip, slice, onMouseMove] ) - const handleMouseLeave = useCallback(() => { - hideTooltip() - setCurrent(null) - }, [hideTooltip]) + const handleMouseLeave = useCallback( + event => { + hideTooltip() + setCurrent(null) + onMouseLeave && onMouseLeave(slice, event) + }, + [hideTooltip, slice, onMouseLeave] + ) + + const handleClick = useCallback( + event => { + onClick && onClick(slice, event) + }, + [slice, onClick] + ) return ( { onMouseEnter={handleMouseEnter} onMouseMove={handleMouseMove} onMouseLeave={handleMouseLeave} + onClick={handleClick} + data-testid={`slice-${slice.id}`} /> ) } @@ -59,6 +85,10 @@ SlicesItem.propTypes = { tooltip: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), isCurrent: PropTypes.bool.isRequired, setCurrent: PropTypes.func.isRequired, + onMouseEnter: PropTypes.func, + onMouseMove: PropTypes.func, + onMouseLeave: PropTypes.func, + onClick: PropTypes.func, } export default memo(SlicesItem) diff --git a/packages/line/tests/Line.test.js b/packages/line/tests/Line.test.js index 7aa0467776..f32e58e6d9 100644 --- a/packages/line/tests/Line.test.js +++ b/packages/line/tests/Line.test.js @@ -148,3 +148,53 @@ describe('curve interpolation', () => { }) } }) + +describe('mouse events on slices', () => { + const data = [ + { + id: 'A', + data: [ + { x: 0, y: 3 }, + { x: 1, y: 7 }, + { x: 2, y: 11 }, + { x: 3, y: 9 }, + { x: 4, y: 8 }, + ], + }, + ] + const baseProps = { + width: 500, + height: 300, + data: data, + animate: false, + enableSlices: 'x', + } + + it('should call onMouseEnter', () => { + const onMouseEnter = jest.fn() + const wrapper = mount() + wrapper.find(`[data-testid='slice-0']`).simulate('mouseenter') + expect(onMouseEnter).toHaveBeenCalledTimes(1) + }) + + it('should call onMouseMove', () => { + const onMouseMove = jest.fn() + const wrapper = mount() + wrapper.find(`[data-testid='slice-0']`).simulate('mousemove') + expect(onMouseMove).toHaveBeenCalledTimes(1) + }) + + it('should call onMouseLeave', () => { + const onMouseLeave = jest.fn() + const wrapper = mount() + wrapper.find(`[data-testid='slice-0']`).simulate('mouseleave') + expect(onMouseLeave).toHaveBeenCalledTimes(1) + }) + + it('should call onClick', () => { + const onClick = jest.fn() + const wrapper = mount() + wrapper.find(`[data-testid='slice-0']`).simulate('click') + expect(onClick).toHaveBeenCalledTimes(1) + }) +})