From e70c4cd5103e689f254a1504481a359c0978cd1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Benitte?= Date: Wed, 15 May 2019 12:02:31 +0900 Subject: [PATCH] feat(bump): add TypeScript definitions for AreaBump --- packages/bump/index.d.ts | 111 ++++++++++++++++++ packages/bump/package.json | 1 + packages/bump/src/area-bump/AnimatedArea.js | 3 + packages/bump/src/area-bump/Area.js | 65 +++++----- packages/bump/src/area-bump/AreaBump.js | 10 ++ packages/bump/src/area-bump/StaticArea.js | 3 + packages/bump/src/area-bump/hooks.js | 61 +++++++++- packages/bump/src/area-bump/props.js | 9 ++ packages/bump/src/bump/props.js | 7 +- .../src/data/components/area-bump/meta.yml | 7 +- .../src/data/components/area-bump/props.js | 42 ++++++- website/src/data/components/bump/meta.yml | 12 +- website/src/pages/area-bump/index.js | 17 ++- 13 files changed, 312 insertions(+), 36 deletions(-) create mode 100644 packages/bump/index.d.ts diff --git a/packages/bump/index.d.ts b/packages/bump/index.d.ts new file mode 100644 index 000000000..8c079eabc --- /dev/null +++ b/packages/bump/index.d.ts @@ -0,0 +1,111 @@ +/* + * This file is part of the nivo project. + * + * Copyright 2016-present, Raphaƫl Benitte. + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +import { Component, MouseEvent } from 'react' +import { Dimensions, Box, Theme, MotionProps, CssMixBlendMode } from '@nivo/core' +import { OrdinalColorsInstruction, InheritedColorProp } from '@nivo/colors' + +declare module '@nivo/bump' { + export interface AreaBumpInputDatum { + x: string | number + y: number + [key: string]: any + } + + export interface AreaBumpInputSerie { + id: string + data: AreaBumpInputDatum[] + [key: string]: any + } + + export interface AreaBumpAreaPoint { + x: number + y0: number + y1: number + } + + export interface AreaBumpPoint { + x: number + y: number + height: number + data: AreaBumpInputDatum + } + + export interface AreaBumpComputedSerie extends AreaBumpInputSerie { + color: string + style: { + fillOpacity: number + borderWidth: number + borderColor: string + borderOpacity: number + } + points: AreaBumpPoint[] + areaPoints: AreaBumpAreaPoint[] + } + + export type AreaBumpAlign = 'start' | 'middle' | 'end' + export type AreaBumpInterpolation = 'smooth' | 'linear' + + export type AreaBumpLayerType = 'grid' | 'axes' | 'labels' | 'areas' + + export type AreaBumpLabelFunction = (serie: AreaBumpComputedSerie) => string + export type AreaBumpLabel = false | string | AreaBumpLabelFunction + + export type AreaBumpMouseHandler = ( + serie: AreaBumpComputedSerie, + event: MouseEvent + ) => void + + export type AreaBumpProps = { + data: AreaBumpInputSerie[] + + margin?: Box + + align?: AreaBumpAlign + interpolation?: AreaBumpInterpolation + spacing?: number + xPadding?: number + + theme?: Theme + colors?: OrdinalColorsInstruction + blendMode?: CssMixBlendMode + fillOpacity?: number + activeFillOpacity?: number + inactiveFillOpacity?: number + borderWidth?: number + activeBorderWidth?: number + inactiveBorderWidth?: number + borderColor?: InheritedColorProp + borderOpacity?: number + activeBorderOpacity?: number + inactiveBorderOpacity?: number + + startLabel?: AreaBumpLabel + startLabelPadding?: number + startLabelTextColor?: InheritedColorProp + endLabel?: AreaBumpLabel + endLabelPadding?: number + endLabelTextColor?: InheritedColorProp + + enableGridX?: boolean + axisTop?: any + axisBottom?: any + + isInteractive?: boolean + onMouseEnter?: AreaBumpMouseHandler + onMouseMove?: AreaBumpMouseHandler + onMouseLeave?: AreaBumpMouseHandler + onClick?: AreaBumpMouseHandler + tooltip?: any + } + + export type AreaBumpSvgProps = AreaBumpProps & MotionProps + + export class AreaBump extends Component {} + export class ResponsiveAreaBump extends Component {} +} diff --git a/packages/bump/package.json b/packages/bump/package.json index 0ac60c169..a67fc9718 100644 --- a/packages/bump/package.json +++ b/packages/bump/package.json @@ -17,6 +17,7 @@ ], "main": "./dist/nivo-bump.cjs.js", "module": "./dist/nivo-bump.esm.js", + "typings": "./index.d.ts", "files": [ "README.md", "LICENSE.md", diff --git a/packages/bump/src/area-bump/AnimatedArea.js b/packages/bump/src/area-bump/AnimatedArea.js index 16710843b..a127a8ebd 100644 --- a/packages/bump/src/area-bump/AnimatedArea.js +++ b/packages/bump/src/area-bump/AnimatedArea.js @@ -17,6 +17,7 @@ const AnimatedArea = ({ onMouseEnter, onMouseMove, onMouseLeave, + onClick, }) => { const { springConfig } = useMotionConfig() @@ -42,6 +43,7 @@ const AnimatedArea = ({ onMouseEnter={onMouseEnter} onMouseMove={onMouseMove} onMouseLeave={onMouseLeave} + onClick={onClick} /> )} @@ -64,6 +66,7 @@ AnimatedArea.propTypes = { onMouseEnter: PropTypes.func, onMouseMove: PropTypes.func, onMouseLeave: PropTypes.func, + onClick: PropTypes.func, } export default memo(AnimatedArea) diff --git a/packages/bump/src/area-bump/Area.js b/packages/bump/src/area-bump/Area.js index 6cafebe4f..e94708c15 100644 --- a/packages/bump/src/area-bump/Area.js +++ b/packages/bump/src/area-bump/Area.js @@ -6,33 +6,35 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ -import React, { memo, useCallback } from 'react' +import React, { memo } from 'react' import PropTypes from 'prop-types' import { useMotionConfig, blendModePropType } from '@nivo/core' -import { useTooltip } from '@nivo/tooltip' -import AreaTooltip from './AreaTooltip' +import { useSerieHandlers } from './hooks' import AnimatedArea from './AnimatedArea' import StaticArea from './StaticArea' -const Area = ({ serie, areaGenerator, blendMode, isInteractive, setCurrentSerie }) => { - const { showTooltipFromEvent, hideTooltip } = useTooltip() - const onMouseEnter = useCallback( - event => { - showTooltipFromEvent(, event) - setCurrentSerie(serie.id) - }, - [serie, showTooltipFromEvent, setCurrentSerie] - ) - const onMouseMove = useCallback( - event => { - showTooltipFromEvent(, event) - }, - [serie, showTooltipFromEvent] - ) - const onMouseLeave = useCallback(() => { - hideTooltip() - setCurrentSerie(null) - }, [hideTooltip, setCurrentSerie]) +const Area = ({ + serie, + areaGenerator, + blendMode, + isInteractive, + onMouseEnter, + onMouseMove, + onMouseLeave, + onClick, + setCurrentSerie, + tooltip, +}) => { + const handlers = useSerieHandlers({ + serie, + isInteractive, + onMouseEnter, + onMouseMove, + onMouseLeave, + onClick, + setCurrent: setCurrentSerie, + tooltip, + }) const { animate } = useMotionConfig() if (animate === true) { @@ -41,9 +43,10 @@ const Area = ({ serie, areaGenerator, blendMode, isInteractive, setCurrentSerie serie={serie} areaGenerator={areaGenerator} blendMode={blendMode} - onMouseEnter={isInteractive ? onMouseEnter : undefined} - onMouseMove={isInteractive ? onMouseMove : undefined} - onMouseLeave={isInteractive ? onMouseLeave : undefined} + onMouseEnter={handlers.onMouseEnter} + onMouseMove={handlers.onMouseMove} + onMouseLeave={handlers.onMouseLeave} + onClick={handlers.onClick} /> ) } @@ -53,9 +56,10 @@ const Area = ({ serie, areaGenerator, blendMode, isInteractive, setCurrentSerie serie={serie} areaGenerator={areaGenerator} blendMode={blendMode} - onMouseEnter={isInteractive ? onMouseEnter : undefined} - onMouseMove={isInteractive ? onMouseMove : undefined} - onMouseLeave={isInteractive ? onMouseLeave : undefined} + onMouseEnter={handlers.onMouseEnter} + onMouseMove={handlers.onMouseMove} + onMouseLeave={handlers.onMouseLeave} + onClick={handlers.onClick} /> ) } @@ -73,7 +77,12 @@ Area.propTypes = { areaGenerator: PropTypes.func.isRequired, blendMode: blendModePropType.isRequired, isInteractive: PropTypes.bool.isRequired, + onMouseEnter: PropTypes.func, + onMouseMove: PropTypes.func, + onMouseLeave: PropTypes.func, + onClick: PropTypes.func, setCurrentSerie: PropTypes.func.isRequired, + tooltip: PropTypes.oneOfType([PropTypes.func, PropTypes.object]).isRequired, } export default memo(Area) diff --git a/packages/bump/src/area-bump/AreaBump.js b/packages/bump/src/area-bump/AreaBump.js index b9d48152c..e8c79e552 100644 --- a/packages/bump/src/area-bump/AreaBump.js +++ b/packages/bump/src/area-bump/AreaBump.js @@ -54,6 +54,11 @@ const AreaBump = props => { axisBottom, isInteractive, + onMouseEnter, + onMouseMove, + onMouseLeave, + onClick, + tooltip, } = props const [currentSerie, setCurrentSerie] = useState(null) @@ -112,6 +117,11 @@ const AreaBump = props => { blendMode={blendMode} isInteractive={isInteractive} setCurrentSerie={setCurrentSerie} + onMouseEnter={onMouseEnter} + onMouseMove={onMouseMove} + onMouseLeave={onMouseLeave} + onClick={onClick} + tooltip={tooltip} /> ))} diff --git a/packages/bump/src/area-bump/StaticArea.js b/packages/bump/src/area-bump/StaticArea.js index 59591ddfb..cbce4462c 100644 --- a/packages/bump/src/area-bump/StaticArea.js +++ b/packages/bump/src/area-bump/StaticArea.js @@ -17,6 +17,7 @@ const StaticArea = ({ onMouseEnter, onMouseMove, onMouseLeave, + onClick, }) => { return ( ) } @@ -50,6 +52,7 @@ StaticArea.propTypes = { onMouseEnter: PropTypes.func, onMouseMove: PropTypes.func, onMouseLeave: PropTypes.func, + onClick: PropTypes.func, } export default memo(StaticArea) diff --git a/packages/bump/src/area-bump/hooks.js b/packages/bump/src/area-bump/hooks.js index e64a8b84e..cdeb104a0 100644 --- a/packages/bump/src/area-bump/hooks.js +++ b/packages/bump/src/area-bump/hooks.js @@ -6,10 +6,11 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ -import { useMemo } from 'react' +import React, { useMemo, useCallback } from 'react' import { area as d3Area, curveBasis, curveLinear } from 'd3-shape' import { useTheme } from '@nivo/core' import { useOrdinalColorScale, useInheritedColor } from '@nivo/colors' +import { useTooltip } from '@nivo/tooltip' import { computeSeries } from './compute' export const useAreaBumpSeries = ({ data, width, height, align, spacing, xPadding }) => @@ -174,3 +175,61 @@ export const useAreaBump = ({ areaGenerator, } } + +export const useSerieHandlers = ({ + serie, + isInteractive, + onMouseEnter, + onMouseMove, + onMouseLeave, + onClick, + setCurrent, + tooltip, +}) => { + const { showTooltipFromEvent, hideTooltip } = useTooltip() + + const handleMouseEnter = useCallback( + event => { + showTooltipFromEvent(React.createElement(tooltip, { serie }), event) + setCurrent(serie.id) + onMouseEnter && onMouseEnter(serie, event) + }, + [serie, onMouseEnter, showTooltipFromEvent, setCurrent] + ) + + const handleMouseMove = useCallback( + event => { + showTooltipFromEvent(React.createElement(tooltip, { serie }), event) + onMouseMove && onMouseMove(serie, event) + }, + [serie, onMouseMove, showTooltipFromEvent] + ) + + const handleMouseLeave = useCallback( + event => { + hideTooltip() + setCurrent(null) + onMouseLeave && onMouseLeave(serie, event) + }, + [serie, onMouseLeave, hideTooltip, setCurrent] + ) + + const handleClick = useCallback( + event => { + onClick && onClick(serie, event) + }, + [serie, onClick] + ) + + const handlers = useMemo( + () => ({ + onMouseEnter: isInteractive ? handleMouseEnter : undefined, + onMouseMove: isInteractive ? handleMouseMove : undefined, + onMouseLeave: isInteractive ? handleMouseLeave : undefined, + onClick: isInteractive ? handleClick : undefined, + }), + [isInteractive, handleMouseEnter, handleMouseMove, handleMouseLeave, handleClick] + ) + + return handlers +} diff --git a/packages/bump/src/area-bump/props.js b/packages/bump/src/area-bump/props.js index 49524d53f..2d54dd6a0 100644 --- a/packages/bump/src/area-bump/props.js +++ b/packages/bump/src/area-bump/props.js @@ -10,6 +10,7 @@ import PropTypes from 'prop-types' import { motionPropTypes, blendModePropType } from '@nivo/core' import { ordinalColorsPropType, inheritedColorPropType } from '@nivo/colors' import { axisPropType } from '@nivo/axes' +import AreaTooltip from './AreaTooltip' const commonPropTypes = { data: PropTypes.arrayOf( @@ -50,15 +51,22 @@ const commonPropTypes = { startLabel: PropTypes.oneOfType([PropTypes.oneOf([false]), PropTypes.string, PropTypes.func]) .isRequired, startLabelPadding: PropTypes.number.isRequired, + startLabelTextColor: inheritedColorPropType.isRequired, endLabel: PropTypes.oneOfType([PropTypes.oneOf([false]), PropTypes.string, PropTypes.func]) .isRequired, endLabelPadding: PropTypes.number.isRequired, + endLabelTextColor: inheritedColorPropType.isRequired, enableGridX: PropTypes.bool.isRequired, axisTop: axisPropType, axisBottom: axisPropType, isInteractive: PropTypes.bool.isRequired, + onMouseEnter: PropTypes.func, + onMouseMove: PropTypes.func, + onMouseLeave: PropTypes.func, + onClick: PropTypes.func, + tooltip: PropTypes.oneOfType([PropTypes.func, PropTypes.object]).isRequired, } export const AreaBumpPropTypes = { @@ -100,6 +108,7 @@ const commonDefaultProps = { axisBottom: {}, isInteractive: true, + tooltip: AreaTooltip, } export const AreaBumpDefaultProps = { diff --git a/packages/bump/src/bump/props.js b/packages/bump/src/bump/props.js index 30a016a1b..88e566e9e 100644 --- a/packages/bump/src/bump/props.js +++ b/packages/bump/src/bump/props.js @@ -8,7 +8,7 @@ */ import PropTypes from 'prop-types' import { motionPropTypes } from '@nivo/core' -import { ordinalColorsPropType } from '@nivo/colors' +import { ordinalColorsPropType, inheritedColorPropType } from '@nivo/colors' import { axisPropType } from '@nivo/axes' const commonPropTypes = { @@ -46,17 +46,20 @@ const commonPropTypes = { startLabel: PropTypes.oneOfType([PropTypes.oneOf([false]), PropTypes.string, PropTypes.func]) .isRequired, startLabelPadding: PropTypes.number.isRequired, + startLabelTextColor: inheritedColorPropType.isRequired, endLabel: PropTypes.oneOfType([PropTypes.oneOf([false]), PropTypes.string, PropTypes.func]) .isRequired, endLabelPadding: PropTypes.number.isRequired, + endLabelTextColor: inheritedColorPropType.isRequired, pointSize: PropTypes.oneOfType([PropTypes.number, PropTypes.func]).isRequired, activePointSize: PropTypes.oneOfType([PropTypes.number, PropTypes.func]).isRequired, inactivePointSize: PropTypes.oneOfType([PropTypes.number, PropTypes.func]).isRequired, - pointColor: PropTypes.any.isRequired, + pointColor: inheritedColorPropType.isRequired, pointBorderWidth: PropTypes.oneOfType([PropTypes.number, PropTypes.func]).isRequired, activePointBorderWidth: PropTypes.oneOfType([PropTypes.number, PropTypes.func]).isRequired, inactivePointBorderWidth: PropTypes.oneOfType([PropTypes.number, PropTypes.func]).isRequired, + pointBorderColor: inheritedColorPropType.isRequired, enableGridX: PropTypes.bool.isRequired, enableGridY: PropTypes.bool.isRequired, diff --git a/website/src/data/components/area-bump/meta.yml b/website/src/data/components/area-bump/meta.yml index 0d545ab31..afbb062a7 100644 --- a/website/src/data/components/area-bump/meta.yml +++ b/website/src/data/components/area-bump/meta.yml @@ -9,6 +9,11 @@ AreaBump: - isomorphic stories: [] description: | - An Area Bump chart. + The AreaBump chart is similar to the [Bump](self:/bump/) chart, + but instead of only showing the ranking over time, it also shows + the values on the y-axis. + + If you're only interested in ranking, you can also you use + the [Bump](self:/bump/) component. The responsive alternative of this component is `ResponsiveAreaBump`. diff --git a/website/src/data/components/area-bump/props.js b/website/src/data/components/area-bump/props.js index 09dd95211..6fc4aa7bc 100644 --- a/website/src/data/components/area-bump/props.js +++ b/website/src/data/components/area-bump/props.js @@ -302,12 +302,52 @@ const props = [ }, { key: 'isInteractive', - help: 'Enable/disable interactivity.', + group: 'Interactivity', type: 'boolean', + help: 'Enable/disable interactivity.', required: false, defaultValue: defaults.isInteractive, controlType: 'switch', + }, + { + key: 'onMouseEnter', + group: 'Interactivity', + type: '(serie, event) => void', + help: 'onMouseEnter handler.', + required: false, + }, + { + key: 'onMouseMove', + group: 'Interactivity', + type: '(serie, event) => void', + help: 'onMouseMove handler.', + required: false, + }, + { + key: 'onMouseLeave', + group: 'Interactivity', + type: '(serie, event) => void', + help: 'onMouseLeave handler.', + required: false, + }, + { + key: 'onClick', + group: 'Interactivity', + type: '(serie, event) => void', + help: 'onClick handler.', + required: false, + }, + { + key: 'tooltip', group: 'Interactivity', + type: 'Function', + required: false, + help: 'Custom tooltip component.', + description: ` + A function allowing complete tooltip customisation, + it must return a valid HTML + element and will receive the series's data. + `, }, ...motionProperties(['svg'], defaults), ] diff --git a/website/src/data/components/bump/meta.yml b/website/src/data/components/bump/meta.yml index cecccc0f1..9c653fb0b 100644 --- a/website/src/data/components/bump/meta.yml +++ b/website/src/data/components/bump/meta.yml @@ -9,4 +9,14 @@ Bump: - isomorphic stories: [] description: | - Bump chart. + The Bump chart can be used to show the ranking of several series + over time. It is quite similar to line charts, + but instead of graphing some measure on the y-axis, + it only shows the ranking of each serie at a given time. + + If you'd like to show the ranking and also graph the + y-axis values, you can also you use the [AreaBump](self:/area-bump/) + component. + + The responsive alternative of this component is `ResponsiveBump`. + diff --git a/website/src/pages/area-bump/index.js b/website/src/pages/area-bump/index.js index 244ad8afe..7812535a7 100644 --- a/website/src/pages/area-bump/index.js +++ b/website/src/pages/area-bump/index.js @@ -8,7 +8,6 @@ */ import React from 'react' import range from 'lodash/range' -import shuffle from 'lodash/shuffle' import random from 'lodash/random' import { ResponsiveAreaBump, AreaBumpDefaultProps } from '@nivo/bump' import ComponentTemplate from '../../components/components/ComponentTemplate' @@ -86,7 +85,21 @@ const Bump = () => { generateData={generateData} > {(properties, data, theme, logAction) => { - return + return ( + + logAction({ + type: 'click', + label: `[serie] ${serie.id}`, + color: serie.color, + data: serie, + }) + } + /> + ) }} )