diff --git a/.travis.yml b/.travis.yml index 9eac9a04..be8ea513 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,8 +13,9 @@ env: - PACKAGE=data-ui-theme - PACKAGE=forms - PACKAGE=network + - PACKAGE=shared script: - - 'cd ./packages/$PACKAGE && npm install && npm run test' + - 'cd ./packages/$PACKAGE && npm install && npm prune && npm run test' - 'cd ../../' - 'eslint --ignore-path=.eslintignore --ext .js,.jsx ./packages/$PACKAGE' after_script: diff --git a/lerna.json b/lerna.json index f2a41ae9..76b544c8 100644 --- a/lerna.json +++ b/lerna.json @@ -3,5 +3,5 @@ "packages": [ "packages/*" ], - "version": "independent" + "version": "0.0.46" } diff --git a/packages/demo/examples/03-sparkline/BarSeriesExamples.jsx b/packages/demo/examples/03-sparkline/BarSeriesExamples.jsx index 5f8c7d08..dc1a9cad 100644 --- a/packages/demo/examples/03-sparkline/BarSeriesExamples.jsx +++ b/packages/demo/examples/03-sparkline/BarSeriesExamples.jsx @@ -8,6 +8,7 @@ import { HorizontalReferenceLine, VerticalReferenceLine, + WithTooltip, PatternLines, LinearGradient, @@ -48,27 +49,41 @@ export default [ - - i + (5 * Math.random()) + (i === 34 ? 5 : 0))} - > - 'max'} - /> - allColors.grape[i === 34 ? 8 : 2]} - fillOpacity={0.7} - renderLabel={(d, i) => (i === 34 ? '🚀' : null)} - /> - - + {(data => ( + + + {({ onMouseMove, onMouseLeave, tooltipData }) => ( + + { + const indexToHighlight = tooltipData ? tooltipData.index : 34; + return allColors.grape[i === indexToHighlight ? 8 : 2]; + }} + fillOpacity={0.7} + renderLabel={(d, i) => { + const indexToHighlight = tooltipData ? tooltipData.index : 34; + return i === indexToHighlight ? '🚀' : null; + }} + /> + (tooltipData ? tooltipData.datum.y.toFixed(2) : 'max')} + /> + + )} + + + ))(range(35).map((_, i) => i + (5 * Math.random()) + (i === 34 ? 5 : 0)))} d.y, }; -const randomData = n => range(n).map(() => (Math.random() * (Math.random() > 0.2 ? 1 : 2))); +const randomData = n => range(n).map((_, i) => ({ + y: Math.random() * (Math.random() > 0.2 ? 1 : 2), + x: `Day ${i + 1}`, +})); + const renderLabel = d => d.toFixed(2); +const renderTooltip = ({ datum }) => ( // eslint-disable-line react/prop-types +
+ {datum.x &&
{datum.x}
} +
{datum.y ? datum.y.toFixed(2) : '--'}
+
+); + export default [ { description: 'Kitchen sink', @@ -46,177 +59,297 @@ export default [ ], example: () => ( - - - allColors.grape[i === 5 ? 8 : 2]} - fillOpacity={0.8} - renderLabel={(d, i) => (i === 5 ? '🤔' : null)} - /> - - - - - - - - - - - - - - - - - - - - - - - - - (i === 0 ? 'left' : 'right')} - /> - - - - - - - - - - - - - - - - - - - - - - - - + {(data => ( + + + {({ onMouseMove, onMouseLeave, tooltipData }) => ( + + { + const indexToHighlight = tooltipData ? tooltipData.index : 5; + return allColors.grape[i === indexToHighlight ? 8 : 2]; + }} + fillOpacity={0.8} + renderLabel={(d, i) => { + const indexToHighlight = tooltipData ? tooltipData.index : 5; + return i === indexToHighlight ? '🤔' : null; + }} + /> + + )} + + + ))(randomData(35))} + + {(data => ( + + + {({ onMouseMove, onMouseLeave, tooltipData }) => ( + + + + + + {tooltipData && [ + , + , + ]} + + )} + + + ))(randomData(25))} + + {(data => ( + + + {({ onMouseMove, onMouseLeave, tooltipData }) => ( + + + + + {tooltipData && [ + , + , + ]} + + )} + + + ))(randomData(25))} + + {(data => ( + + + {({ onMouseMove, onMouseLeave, tooltipData }) => ( + + + + (i === 0 ? 'left' : 'right')} + /> + {tooltipData && [ + , + , + ]} + + )} + + + ))(randomData(25))} + + {(data => ( + + + {({ onMouseMove, onMouseLeave, tooltipData }) => ( + + + + + + + + + {tooltipData && [ + , + , + ]} + + )} + + + ))(randomData(45))} + + {(data => ( + + + {({ onMouseMove, onMouseLeave, tooltipData }) => ( + + + + + + + {tooltipData && [ + , + , + ]} + + )} + + + ))(randomData(35))} ), }, diff --git a/packages/demo/examples/03-sparkline/LineSeriesExamples.jsx b/packages/demo/examples/03-sparkline/LineSeriesExamples.jsx index ab07b375..09f39d75 100644 --- a/packages/demo/examples/03-sparkline/LineSeriesExamples.jsx +++ b/packages/demo/examples/03-sparkline/LineSeriesExamples.jsx @@ -11,6 +11,7 @@ import { BandLine, HorizontalReferenceLine, VerticalReferenceLine, + WithTooltip, PatternLines, LinearGradient, @@ -60,24 +61,46 @@ export default [
- - (Math.random() * (Math.random() > 0.2 ? 1 : 2)))} - > - - - - + {(data => ( + + datum.y.toFixed(2)} > + {({ onMouseMove, onMouseLeave, tooltipData }) => ( + + + + + {tooltipData && [ + , + , + ]} + + )} + + + ))(range(40).map(() => (Math.random() * (Math.random() > 0.2 ? 1 : 2))))} - - - {range(30).map((_, i) => ( - - ))} - - - - + {(data => + ( + datum.y.toFixed(2)}> + {({ onMouseMove, onMouseLeave, tooltipData }) => ( + + {range(30).map((_, i) => ( + + ))} + + + + {tooltipData && [ + , + , + , + ]} + + )} + + ))(randomData(30))} ( - - ), - renderTooltip: null, - styles: { display: 'inline-block', position: 'relative' }, - TooltipComponent: TooltipWithBounds, - tooltipTimeout: 200, -}; - -class WithTooltip extends React.PureComponent { - constructor(props) { - super(props); - this.handleMouseMove = this.handleMouseMove.bind(this); - this.handleMouseLeave = this.handleMouseLeave.bind(this); - this.tooltipTimeout = null; - } - - handleMouseMove({ event, datum, data, ...rest }) { - if (this.tooltipTimeout) clearTimeout(this.tooltipTimeout); - - let coords = { x: 0, y: 0 }; - if (event && event.target && event.target.ownerSVGElement) { - coords = localPoint(event.target.ownerSVGElement, event); - } - - this.props.showTooltip({ - tooltipLeft: coords.x + 10, - tooltipTop: coords.y + 10, - tooltipData: { - event, - datum, - data, - ...rest, - }, - }); - } - - handleMouseLeave() { - const { tooltipTimeout, hideTooltip } = this.props; - this.tooltipTimeout = setTimeout(() => { hideTooltip(); }, tooltipTimeout); - } - - render() { - const { - children, - className, - HoverStyles, - tooltipData, - tooltipOpen, - tooltipLeft, - tooltipTop, - renderTooltip, - styles, - TooltipComponent, - } = this.props; - - const childProps = { - onMouseMove: this.handleMouseMove, - onMouseLeave: this.handleMouseLeave, - tooltipData, - }; - - return ( -
- - {/* inject props or pass to a function depending on child */} - {typeof children === 'function' - ? children(childProps) - : React.cloneElement(React.Children.only(children), childProps)} - - {tooltipOpen && TooltipComponent && renderTooltip && - - {renderTooltip(tooltipData)} - } - - {HoverStyles && } -
- ); - } -} - -WithTooltip.propTypes = propTypes; -WithTooltip.defaultProps = defaultProps; - -export default withTooltip(WithTooltip); diff --git a/packages/histogram/src/index.js b/packages/histogram/src/index.js index 89a8705f..e2623d26 100644 --- a/packages/histogram/src/index.js +++ b/packages/histogram/src/index.js @@ -5,7 +5,7 @@ export { default as DensitySeries } from './series/DensitySeries'; export { default as XAxis } from './axis/XAxis'; export { default as YAxis } from './axis/YAxis'; -export { default as WithTooltip, withTooltipPropTypes } from './enhancer/WithTooltip'; +export { default as WithTooltip, withTooltipPropTypes } from '@data-ui/shared/build/enhancer/WithTooltip'; export { LinearGradient } from '@vx/gradient'; export { PatternLines } from '@vx/pattern'; diff --git a/packages/histogram/test/enhancer/WithTooltip.test.js b/packages/histogram/test/enhancer/WithTooltip.test.js deleted file mode 100644 index 41b86248..00000000 --- a/packages/histogram/test/enhancer/WithTooltip.test.js +++ /dev/null @@ -1,157 +0,0 @@ -import React from 'react'; -import { render, mount } from 'enzyme'; - -import { WithTooltip, withTooltipPropTypes } from '../../src'; - -describe('', () => { - test('WithTooltip should be defined', () => { - expect(WithTooltip).toBeDefined(); - }); - - test('withTooltipPropTypes should be defined', () => { - expect(withTooltipPropTypes).toBeDefined(); - }); - - test('it should render component-type children and call function-type children', () => { - function MyComponent() { - return
; - } - - let wrapper = render( - null}> - {MyComponent} - , - ); - expect(wrapper.find('#test').length).toBe(1); - - wrapper = render( - null}> - {} - , - ); - expect(wrapper.find('#test').length).toBe(1); - }); - - test('it should pass onMouseMove, onMouseLeave, tooltipData to children', () => { - let data; - let mouseMove; - function MyComponent({ onMouseMove, onMouseLeave, tooltipData }) { - expect(onMouseMove).toBeDefined(); - expect(onMouseLeave).toBeDefined(); - mouseMove = onMouseMove; - data = tooltipData; - return null; - } - - mount( - null}> - {MyComponent} - , - ); - - mouseMove({}); - expect(data).toBeDefined(); - data = null; - - mount( - null}> - {} - , - ); - - mouseMove({}); - expect(data).toBeDefined(); - }); - - test('it should render the return value of renderTooltip on mouse move', () => { - const renderTooltip = jest.fn(); - renderTooltip.mockReturnValue(
); - - let mouseMove; - const wrapper = mount( - - {({ onMouseMove }) => { - mouseMove = onMouseMove; - return ; - }} - , - ); - - mouseMove({}); - wrapper.update(); - expect(renderTooltip).toHaveBeenCalledTimes(1); - expect(wrapper.find('#test').length).toBe(1); - }); - - test('it should hide the value of renderTooltip on mouse leave', () => { - jest.useFakeTimers(); // needed for mouseLeave timeout - - const renderTooltip = jest.fn(); - renderTooltip.mockReturnValue(
); - - let mouseMove; - let mouseLeave; - const wrapper = mount( - - {({ onMouseMove, onMouseLeave }) => { - mouseMove = onMouseMove; - mouseLeave = onMouseLeave; - return null; - }} - , - ); - - mouseMove({}); - wrapper.update(); - expect(renderTooltip).toHaveBeenCalledTimes(1); - expect(wrapper.find('#test').length).toBe(1); - - mouseLeave({}); - jest.runAllTimers(); - wrapper.update(); - expect(wrapper.find('#test').length).toBe(0); - }); - - test('it should render the passed TooltipComponent and pass it left and top props', () => { - function Tooltip({ left, top }) { // eslint-disable-line - expect(left).toEqual(expect.any(Number)); - expect(top).toEqual(expect.any(Number)); - return
; - } - - let mouseMove; - const wrapper = mount( - null} - TooltipComponent={Tooltip} - > - {({ onMouseMove }) => { - mouseMove = onMouseMove; - }} - , - ); - - mouseMove({}); - wrapper.update(); - expect(wrapper.find('#test').length).toBe(1); - }); - - test('it should pass className and styles props to the wrapper container', () => { - const styles = { color: 'pink' }; - const className = 'i-like-tooltipz'; - - const wrapper = render( - null} - className={className} - styles={styles} - > - {() => null} - , - ); - - const container = wrapper.find('.i-like-tooltipz'); - expect(container.length).toBe(1); - expect(container.prop('style')).toMatchObject(styles); - }); -}); diff --git a/packages/network/package.json b/packages/network/package.json index c4f86f65..2e36afa8 100644 --- a/packages/network/package.json +++ b/packages/network/package.json @@ -47,6 +47,7 @@ "react": "^15.0.0-0 || ^16.0.0-0" }, "dependencies": { + "@data-ui/shared": "0.0.0", "@data-ui/theme": "0.0.9", "@vx/event": "0.0.141", "@vx/glyph": "0.0.140", diff --git a/packages/network/src/chart/Network.jsx b/packages/network/src/chart/Network.jsx index 6986f627..9c3c2d77 100644 --- a/packages/network/src/chart/Network.jsx +++ b/packages/network/src/chart/Network.jsx @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import React from 'react'; import { Group } from '@vx/group'; -import WithTooltip, { withTooltipPropTypes } from '../enhancer/WithTooltip'; +import WithTooltip, { withTooltipPropTypes } from '@data-ui/shared/build/enhancer/WithTooltip'; import Layout from '../layout/atlasForce'; import Links from './Links'; import Nodes from './Nodes'; diff --git a/packages/network/src/enhancer/WithTooltip.jsx b/packages/network/src/enhancer/WithTooltip.jsx deleted file mode 100644 index e73edc5a..00000000 --- a/packages/network/src/enhancer/WithTooltip.jsx +++ /dev/null @@ -1,122 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import { localPoint } from '@vx/event'; - -import { - withTooltip, - TooltipWithBounds, - withTooltipPropTypes as vxTooltipPropTypes, -} from '@vx/tooltip'; - -export const withTooltipPropTypes = { - onMouseMove: PropTypes.func, // expects to be called like func({ event, index, id, data }) - onMouseLeave: PropTypes.func, // expects to be called like func({ event, index, id, data }) - tooltipData: PropTypes.any, -}; - -const propTypes = { - ...vxTooltipPropTypes, - children: PropTypes.oneOfType([PropTypes.object, PropTypes.func]).isRequired, - className: PropTypes.string, - HoverStyles: PropTypes.oneOfType([PropTypes.object, PropTypes.func]), - renderTooltip: PropTypes.func, - styles: PropTypes.object, - TooltipComponent: PropTypes.oneOfType([PropTypes.object, PropTypes.func]), -}; - -const defaultProps = { - className: null, - HoverStyles: () => ( - - ), - renderTooltip: null, - styles: { display: 'inline-block', position: 'relative' }, - TooltipComponent: TooltipWithBounds, - tooltipTimeout: 200, -}; - -class WithTooltip extends React.PureComponent { - constructor(props) { - super(props); - this.handleMouseMove = this.handleMouseMove.bind(this); - this.handleMouseLeave = this.handleMouseLeave.bind(this); - this.tooltipTimeout = null; - } - - handleMouseMove({ event, datum, data, ...rest }) { - if (this.tooltipTimeout) clearTimeout(this.tooltipTimeout); - let coords = { x: 0, y: 0 }; - if (event && event.target && event.target.ownerSVGElement) { - coords = localPoint(event); - } - - this.props.showTooltip({ - tooltipLeft: coords.x + 10, - tooltipTop: coords.y + 10, - tooltipData: { - event, - datum, - data, - ...rest, - }, - }); - } - - handleMouseLeave() { - const { tooltipTimeout, hideTooltip } = this.props; - this.tooltipTimeout = setTimeout(() => { hideTooltip(); }, tooltipTimeout); - } - - render() { - const { - children, - className, - HoverStyles, - tooltipData, - tooltipOpen, - tooltipLeft, - tooltipTop, - renderTooltip, - styles, - TooltipComponent, - } = this.props; - - const childProps = { - onMouseMove: this.handleMouseMove, - onMouseLeave: this.handleMouseLeave, - tooltipData, - }; - - return ( -
- - {/* inject props or pass to a function depending on child */} - {typeof children === 'function' - ? children(childProps) - : React.cloneElement(React.Children.only(children), childProps)} - - {tooltipOpen && TooltipComponent && renderTooltip && - - {renderTooltip(tooltipData)} - } - - {HoverStyles && } -
- ); - } -} - -WithTooltip.propTypes = propTypes; -WithTooltip.defaultProps = defaultProps; - -export default withTooltip(WithTooltip); diff --git a/packages/network/src/index.js b/packages/network/src/index.js index e64700a6..7469fbce 100644 --- a/packages/network/src/index.js +++ b/packages/network/src/index.js @@ -14,4 +14,4 @@ export { export { default as WithTooltip, withTooltipPropTypes, -} from './enhancer/WithTooltip'; +} from '@data-ui/shared/build/enhancer/WithTooltip'; diff --git a/packages/network/test/enhancer/WithTooltip.test.js b/packages/network/test/enhancer/WithTooltip.test.js deleted file mode 100644 index 41b86248..00000000 --- a/packages/network/test/enhancer/WithTooltip.test.js +++ /dev/null @@ -1,157 +0,0 @@ -import React from 'react'; -import { render, mount } from 'enzyme'; - -import { WithTooltip, withTooltipPropTypes } from '../../src'; - -describe('', () => { - test('WithTooltip should be defined', () => { - expect(WithTooltip).toBeDefined(); - }); - - test('withTooltipPropTypes should be defined', () => { - expect(withTooltipPropTypes).toBeDefined(); - }); - - test('it should render component-type children and call function-type children', () => { - function MyComponent() { - return
; - } - - let wrapper = render( - null}> - {MyComponent} - , - ); - expect(wrapper.find('#test').length).toBe(1); - - wrapper = render( - null}> - {} - , - ); - expect(wrapper.find('#test').length).toBe(1); - }); - - test('it should pass onMouseMove, onMouseLeave, tooltipData to children', () => { - let data; - let mouseMove; - function MyComponent({ onMouseMove, onMouseLeave, tooltipData }) { - expect(onMouseMove).toBeDefined(); - expect(onMouseLeave).toBeDefined(); - mouseMove = onMouseMove; - data = tooltipData; - return null; - } - - mount( - null}> - {MyComponent} - , - ); - - mouseMove({}); - expect(data).toBeDefined(); - data = null; - - mount( - null}> - {} - , - ); - - mouseMove({}); - expect(data).toBeDefined(); - }); - - test('it should render the return value of renderTooltip on mouse move', () => { - const renderTooltip = jest.fn(); - renderTooltip.mockReturnValue(
); - - let mouseMove; - const wrapper = mount( - - {({ onMouseMove }) => { - mouseMove = onMouseMove; - return ; - }} - , - ); - - mouseMove({}); - wrapper.update(); - expect(renderTooltip).toHaveBeenCalledTimes(1); - expect(wrapper.find('#test').length).toBe(1); - }); - - test('it should hide the value of renderTooltip on mouse leave', () => { - jest.useFakeTimers(); // needed for mouseLeave timeout - - const renderTooltip = jest.fn(); - renderTooltip.mockReturnValue(
); - - let mouseMove; - let mouseLeave; - const wrapper = mount( - - {({ onMouseMove, onMouseLeave }) => { - mouseMove = onMouseMove; - mouseLeave = onMouseLeave; - return null; - }} - , - ); - - mouseMove({}); - wrapper.update(); - expect(renderTooltip).toHaveBeenCalledTimes(1); - expect(wrapper.find('#test').length).toBe(1); - - mouseLeave({}); - jest.runAllTimers(); - wrapper.update(); - expect(wrapper.find('#test').length).toBe(0); - }); - - test('it should render the passed TooltipComponent and pass it left and top props', () => { - function Tooltip({ left, top }) { // eslint-disable-line - expect(left).toEqual(expect.any(Number)); - expect(top).toEqual(expect.any(Number)); - return
; - } - - let mouseMove; - const wrapper = mount( - null} - TooltipComponent={Tooltip} - > - {({ onMouseMove }) => { - mouseMove = onMouseMove; - }} - , - ); - - mouseMove({}); - wrapper.update(); - expect(wrapper.find('#test').length).toBe(1); - }); - - test('it should pass className and styles props to the wrapper container', () => { - const styles = { color: 'pink' }; - const className = 'i-like-tooltipz'; - - const wrapper = render( - null} - className={className} - styles={styles} - > - {() => null} - , - ); - - const container = wrapper.find('.i-like-tooltipz'); - expect(container.length).toBe(1); - expect(container.prop('style')).toMatchObject(styles); - }); -}); diff --git a/packages/radial-chart/package.json b/packages/radial-chart/package.json index e8de11df..30fa3cc9 100644 --- a/packages/radial-chart/package.json +++ b/packages/radial-chart/package.json @@ -22,6 +22,7 @@ "author": "Chris Williams ", "license": "MIT", "dependencies": { + "@data-ui/shared": "0.0.0", "@data-ui/theme": "0.0.9", "@vx/event": "0.0.140", "@vx/group": "0.0.140", diff --git a/packages/radial-chart/src/chart/RadialChart.jsx b/packages/radial-chart/src/chart/RadialChart.jsx index 1ba8b663..544e074a 100644 --- a/packages/radial-chart/src/chart/RadialChart.jsx +++ b/packages/radial-chart/src/chart/RadialChart.jsx @@ -2,7 +2,7 @@ import { Group } from '@vx/group'; import PropTypes from 'prop-types'; import React from 'react'; -import WithTooltip, { withTooltipPropTypes } from '../enhancer/WithTooltip'; +import WithTooltip, { withTooltipPropTypes } from '@data-ui/shared/build/enhancer/WithTooltip'; export const propTypes = { ...withTooltipPropTypes, diff --git a/packages/radial-chart/src/enhancer/WithTooltip.jsx b/packages/radial-chart/src/enhancer/WithTooltip.jsx deleted file mode 100644 index 709305d5..00000000 --- a/packages/radial-chart/src/enhancer/WithTooltip.jsx +++ /dev/null @@ -1,121 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import { localPoint } from '@vx/event'; - -import { - withTooltip, - TooltipWithBounds, - withTooltipPropTypes as vxTooltipPropTypes, -} from '@vx/tooltip'; - -export const withTooltipPropTypes = { - onMouseMove: PropTypes.func, // expects to be called like func({ event, datum, data }) - onMouseLeave: PropTypes.func, // expects to be called like func({ event, datum, data }) - tooltipData: PropTypes.any, -}; - -const propTypes = { - ...vxTooltipPropTypes, - children: PropTypes.oneOfType([PropTypes.object, PropTypes.func]).isRequired, - className: PropTypes.string, - HoverStyles: PropTypes.oneOfType([PropTypes.object, PropTypes.func]), - renderTooltip: PropTypes.func, - styles: PropTypes.object, - TooltipComponent: PropTypes.oneOfType([PropTypes.object, PropTypes.func]), -}; - -const defaultProps = { - className: null, - HoverStyles: () => ( - - ), - renderTooltip: null, - styles: { display: 'inline-block', position: 'relative' }, - TooltipComponent: TooltipWithBounds, - tooltipTimeout: 200, -}; - -class WithTooltip extends React.PureComponent { - constructor(props) { - super(props); - this.handleMouseMove = this.handleMouseMove.bind(this); - this.handleMouseLeave = this.handleMouseLeave.bind(this); - this.tooltipTimeout = null; - } - - handleMouseMove({ event, datum, ...rest }) { - if (this.tooltipTimeout) clearTimeout(this.tooltipTimeout); - - let coords = { x: 0, y: 0 }; - if (event && event.target && event.target.ownerSVGElement) { - coords = localPoint(event.target.ownerSVGElement, event); - } - - this.props.showTooltip({ - tooltipLeft: coords.x + 10, - tooltipTop: coords.y + 10, - tooltipData: { - event, - datum, - ...rest, - }, - }); - } - - handleMouseLeave() { - const { tooltipTimeout, hideTooltip } = this.props; - this.tooltipTimeout = setTimeout(() => { hideTooltip(); }, tooltipTimeout); - } - - render() { - const { - children, - className, - HoverStyles, - tooltipData, - tooltipOpen, - tooltipLeft, - tooltipTop, - renderTooltip, - styles, - TooltipComponent, - } = this.props; - - const childProps = { - onMouseMove: this.handleMouseMove, - onMouseLeave: this.handleMouseLeave, - tooltipData, - }; - - return ( -
- - {/* inject props or pass to a function depending on child */} - {typeof children === 'function' - ? children(childProps) - : React.cloneElement(React.Children.only(children), childProps)} - - {tooltipOpen && TooltipComponent && renderTooltip && - - {renderTooltip(tooltipData)} - } - - {HoverStyles && } -
- ); - } -} - -WithTooltip.propTypes = propTypes; -WithTooltip.defaultProps = defaultProps; - -export default withTooltip(WithTooltip); diff --git a/packages/radial-chart/src/index.js b/packages/radial-chart/src/index.js index 4840a223..09fc62c2 100644 --- a/packages/radial-chart/src/index.js +++ b/packages/radial-chart/src/index.js @@ -2,4 +2,4 @@ export { default as ArcLabel } from './label/ArcLabel'; export { default as ArcSeries } from './series/ArcSeries'; export { default as RadialChart, propTypes as radialChartPropTypes } from './chart/RadialChart'; export { singleHueScaleFactory, multiHueScaleFactory } from './util/fillScaleFactory'; -export { default as WithTooltip, withTooltipPropTypes } from './enhancer/WithTooltip'; +export { default as WithTooltip, withTooltipPropTypes } from '@data-ui/shared/build/enhancer/WithTooltip'; diff --git a/packages/radial-chart/test/WithTooltip.test.js b/packages/radial-chart/test/WithTooltip.test.js deleted file mode 100644 index 76da29b1..00000000 --- a/packages/radial-chart/test/WithTooltip.test.js +++ /dev/null @@ -1,157 +0,0 @@ -import React from 'react'; -import { render, mount } from 'enzyme'; - -import { WithTooltip, withTooltipPropTypes } from '../src'; - -describe('', () => { - test('WithTooltip should be defined', () => { - expect(WithTooltip).toBeDefined(); - }); - - test('withTooltipPropTypes should be defined', () => { - expect(withTooltipPropTypes).toBeDefined(); - }); - - test('it should render component-type children and call function-type children', () => { - function MyComponent() { - return
; - } - - let wrapper = render( - null}> - {MyComponent} - , - ); - expect(wrapper.find('#test').length).toBe(1); - - wrapper = render( - null}> - {} - , - ); - expect(wrapper.find('#test').length).toBe(1); - }); - - test('it should pass onMouseMove, onMouseLeave, tooltipData to children', () => { - let data; - let mouseMove; - function MyComponent({ onMouseMove, onMouseLeave, tooltipData }) { - expect(onMouseMove).toBeDefined(); - expect(onMouseLeave).toBeDefined(); - mouseMove = onMouseMove; - data = tooltipData; - return null; - } - - mount( - null}> - {MyComponent} - , - ); - - mouseMove({}); - expect(data).toBeDefined(); - data = null; - - mount( - null}> - {} - , - ); - - mouseMove({}); - expect(data).toBeDefined(); - }); - - test('it should render the return value of renderTooltip on mouse move', () => { - const renderTooltip = jest.fn(); - renderTooltip.mockReturnValue(
); - - let mouseMove; - const wrapper = mount( - - {({ onMouseMove }) => { - mouseMove = onMouseMove; - return ; - }} - , - ); - - mouseMove({}); - wrapper.update(); - expect(renderTooltip).toHaveBeenCalledTimes(1); - expect(wrapper.find('#test').length).toBe(1); - }); - - test('it should hide the value of renderTooltip on mouse leave', () => { - jest.useFakeTimers(); // needed for mouseLeave timeout - - const renderTooltip = jest.fn(); - renderTooltip.mockReturnValue(
); - - let mouseMove; - let mouseLeave; - const wrapper = mount( - - {({ onMouseMove, onMouseLeave }) => { - mouseMove = onMouseMove; - mouseLeave = onMouseLeave; - return null; - }} - , - ); - - mouseMove({}); - wrapper.update(); - expect(renderTooltip).toHaveBeenCalledTimes(1); - expect(wrapper.find('#test').length).toBe(1); - - mouseLeave({}); - jest.runAllTimers(); - wrapper.update(); - expect(wrapper.find('#test').length).toBe(0); - }); - - test('it should render the passed TooltipComponent and pass it left and top props', () => { - function Tooltip({ left, top }) { // eslint-disable-line - expect(left).toEqual(expect.any(Number)); - expect(top).toEqual(expect.any(Number)); - return
; - } - - let mouseMove; - const wrapper = mount( - null} - TooltipComponent={Tooltip} - > - {({ onMouseMove }) => { - mouseMove = onMouseMove; - }} - , - ); - - mouseMove({}); - wrapper.update(); - expect(wrapper.find('#test').length).toBe(1); - }); - - test('it should pass className and styles props to the wrapper container', () => { - const styles = { color: 'pink' }; - const className = 'i-like-tooltipz'; - - const wrapper = render( - null} - className={className} - styles={styles} - > - {() => null} - , - ); - - const container = wrapper.find('.i-like-tooltipz'); - expect(container.length).toBe(1); - expect(container.prop('style')).toMatchObject(styles); - }); -}); diff --git a/packages/shared/.babelrc b/packages/shared/.babelrc new file mode 100644 index 00000000..44157e5b --- /dev/null +++ b/packages/shared/.babelrc @@ -0,0 +1,19 @@ +{ + "presets": ["es2015", "react", "stage-0"], + "plugins": [], + "env": { + "development": { + "plugins": [ + ["react-transform", { + "transforms": [{ + "transform": "react-transform-hmr", + "imports": ["react"], + "locals": ["module"] + }] + }], + "transform-runtime", + "transform-decorators-legacy" + ] + } + } +} diff --git a/packages/shared/Makefile b/packages/shared/Makefile new file mode 100644 index 00000000..f7e19ad0 --- /dev/null +++ b/packages/shared/Makefile @@ -0,0 +1 @@ +include node_modules/react-fatigue-dev/Makefile diff --git a/packages/shared/README.md b/packages/shared/README.md new file mode 100644 index 00000000..8acff69a --- /dev/null +++ b/packages/shared/README.md @@ -0,0 +1,9 @@ +# @data-ui/shared + +Shared ``@data-ui` components used across multiple packages. + +`npm install --save @data-ui/shared` + + + + diff --git a/packages/shared/package.json b/packages/shared/package.json new file mode 100644 index 00000000..b88c3b14 --- /dev/null +++ b/packages/shared/package.json @@ -0,0 +1,64 @@ +{ + "name": "@data-ui/shared", + "version": "0.0.0", + "description": "Shared @data-ui components used across multiple packages", + "main": "build/index.js", + "files": [ + "build" + ], + "scripts": { + "build": "make build SRC=./src", + "prepublish": "make build SRC=./src", + "test": "jest --verbose --coverage --color" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/williaster/data-ui.git" + }, + "keywords": [ + "vx", + "react", + "d3", + "visualization", + "graph", + "chart", + "data" + ], + "author": "Chris Williams @williaster", + "license": "MIT", + "bugs": { + "url": "https://github.com/williaster/data-ui/issues" + }, + "homepage": "https://github.com/williaster/data-ui#readme", + "devDependencies": { + "babel-jest": "^20.0.3", + "babel-polyfill": "^6.23.0", + "enzyme": "^3.1.0", + "enzyme-adapter-react-16": "^1.0.0", + "jest": "^20.0.3", + "react": "^16.0.0", + "react-dom": "^16.0.0", + "react-fatigue-dev": "github:tj/react-fatigue-dev", + "react-test-renderer": "^16.0.0", + "react-tools": "^0.10.0", + "regenerator-runtime": "^0.10.5" + }, + "peerDependencies": { + "react": "^15.0.0-0 || ^16.0.0-0" + }, + "dependencies": { + "@data-ui/theme": "0.0.9", + "@vx/event": "0.0.143", + "@vx/group": "0.0.143", + "@vx/shape": "0.0.145", + "@vx/tooltip": "0.0.143", + "d3-array": "^1.2.1", + "prop-types": "^15.5.10" + }, + "jest": { + "setupFiles": [ + "/test/shim.js", + "/test/setup.js" + ] + } +} diff --git a/packages/xy-chart/src/enhancer/WithTooltip.jsx b/packages/shared/src/enhancer/WithTooltip.js similarity index 94% rename from packages/xy-chart/src/enhancer/WithTooltip.jsx rename to packages/shared/src/enhancer/WithTooltip.js index 18296f62..aa22ae1d 100644 --- a/packages/xy-chart/src/enhancer/WithTooltip.jsx +++ b/packages/shared/src/enhancer/WithTooltip.js @@ -5,6 +5,8 @@ import localPoint from '@vx/event/build/localPoint'; import withTooltip from '@vx/tooltip/build/enhancers/withTooltip'; import TooltipWithBounds, { withTooltipPropTypes as vxTooltipPropTypes } from '@vx/tooltip/build/tooltips/TooltipWithBounds'; +export { default as Tooltip } from '@vx/tooltip/build/tooltips/Tooltip'; + export const withTooltipPropTypes = { onMouseMove: PropTypes.func, // expects to be called like func({ event, datum }) onMouseLeave: PropTypes.func, // expects to be called like func({ event, datum }) @@ -25,6 +27,7 @@ const defaultProps = { className: null, HoverStyles: () => (