From 23a5783b440c2ccf624692af851e7cf0d8735190 Mon Sep 17 00:00:00 2001 From: plouc Date: Sat, 19 Feb 2022 06:51:16 +0900 Subject: [PATCH 1/3] chore(line): remove old license headers --- packages/line/src/Areas.js | 8 -------- packages/line/src/Line.js | 8 -------- packages/line/src/LineCanvas.js | 8 -------- packages/line/src/Lines.js | 8 -------- packages/line/src/LinesItem.js | 8 -------- packages/line/src/Mesh.js | 8 -------- packages/line/src/PointTooltip.js | 8 -------- packages/line/src/Points.js | 8 -------- packages/line/src/ResponsiveLine.js | 8 -------- packages/line/src/ResponsiveLineCanvas.js | 8 -------- packages/line/src/SliceTooltip.js | 8 -------- packages/line/src/Slices.js | 8 -------- packages/line/src/SlicesItem.js | 8 -------- packages/line/src/hooks.js | 8 -------- packages/line/src/index.js | 8 -------- packages/line/src/props.js | 8 -------- packages/line/stories/LineCanvas.stories.js | 8 -------- packages/line/stories/ResponsiveLineCanvas.stories.js | 8 -------- packages/line/stories/line.stories.js | 8 -------- 19 files changed, 152 deletions(-) diff --git a/packages/line/src/Areas.js b/packages/line/src/Areas.js index c459aa4b14..aa7de94555 100644 --- a/packages/line/src/Areas.js +++ b/packages/line/src/Areas.js @@ -1,11 +1,3 @@ -/* - * 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 { memo } from 'react' import PropTypes from 'prop-types' import { useSpring, animated } from '@react-spring/web' diff --git a/packages/line/src/Line.js b/packages/line/src/Line.js index 7956479100..71c52085ce 100644 --- a/packages/line/src/Line.js +++ b/packages/line/src/Line.js @@ -1,11 +1,3 @@ -/* - * 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 { Fragment, useState } from 'react' import { bindDefs, diff --git a/packages/line/src/LineCanvas.js b/packages/line/src/LineCanvas.js index d47660d152..60db3aed38 100644 --- a/packages/line/src/LineCanvas.js +++ b/packages/line/src/LineCanvas.js @@ -1,11 +1,3 @@ -/* - * 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 { createElement, useRef, useEffect, useState, useCallback, forwardRef } from 'react' import { withContainer, diff --git a/packages/line/src/Lines.js b/packages/line/src/Lines.js index 8e38885c0f..04582a8a8c 100644 --- a/packages/line/src/Lines.js +++ b/packages/line/src/Lines.js @@ -1,11 +1,3 @@ -/* - * 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 { memo } from 'react' import PropTypes from 'prop-types' import LinesItem from './LinesItem' diff --git a/packages/line/src/LinesItem.js b/packages/line/src/LinesItem.js index a85c6b6989..e7b698293c 100644 --- a/packages/line/src/LinesItem.js +++ b/packages/line/src/LinesItem.js @@ -1,11 +1,3 @@ -/* - * 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 { memo, useMemo } from 'react' import PropTypes from 'prop-types' import { animated } from '@react-spring/web' diff --git a/packages/line/src/Mesh.js b/packages/line/src/Mesh.js index b04b5e38a1..ecb827aeb3 100644 --- a/packages/line/src/Mesh.js +++ b/packages/line/src/Mesh.js @@ -1,11 +1,3 @@ -/* - * 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 { createElement, memo, useCallback } from 'react' import PropTypes from 'prop-types' import { useTooltip } from '@nivo/tooltip' diff --git a/packages/line/src/PointTooltip.js b/packages/line/src/PointTooltip.js index 6436ad6aa4..bd5104606f 100644 --- a/packages/line/src/PointTooltip.js +++ b/packages/line/src/PointTooltip.js @@ -1,11 +1,3 @@ -/* - * 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 { memo } from 'react' import PropTypes from 'prop-types' import { BasicTooltip } from '@nivo/tooltip' diff --git a/packages/line/src/Points.js b/packages/line/src/Points.js index 09fcf15b7d..c6f70791cc 100644 --- a/packages/line/src/Points.js +++ b/packages/line/src/Points.js @@ -1,11 +1,3 @@ -/* - * 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 { memo } from 'react' import PropTypes from 'prop-types' import { getLabelGenerator, DotsItem, useTheme } from '@nivo/core' diff --git a/packages/line/src/ResponsiveLine.js b/packages/line/src/ResponsiveLine.js index dfa5ce089d..e60b0a80b4 100644 --- a/packages/line/src/ResponsiveLine.js +++ b/packages/line/src/ResponsiveLine.js @@ -1,11 +1,3 @@ -/* - * 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 { ResponsiveWrapper } from '@nivo/core' import Line from './Line' diff --git a/packages/line/src/ResponsiveLineCanvas.js b/packages/line/src/ResponsiveLineCanvas.js index 05b99f18d4..c1416d58b9 100644 --- a/packages/line/src/ResponsiveLineCanvas.js +++ b/packages/line/src/ResponsiveLineCanvas.js @@ -1,11 +1,3 @@ -/* - * 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 { forwardRef } from 'react' import { ResponsiveWrapper } from '@nivo/core' import LineCanvas from './LineCanvas' diff --git a/packages/line/src/SliceTooltip.js b/packages/line/src/SliceTooltip.js index c570f22745..7609020c42 100644 --- a/packages/line/src/SliceTooltip.js +++ b/packages/line/src/SliceTooltip.js @@ -1,11 +1,3 @@ -/* - * 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 { memo } from 'react' import PropTypes from 'prop-types' import { useTheme } from '@nivo/core' diff --git a/packages/line/src/Slices.js b/packages/line/src/Slices.js index 952688cfee..9bdad7792d 100644 --- a/packages/line/src/Slices.js +++ b/packages/line/src/Slices.js @@ -1,11 +1,3 @@ -/* - * 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 { memo } from 'react' import PropTypes from 'prop-types' import SlicesItem from './SlicesItem' diff --git a/packages/line/src/SlicesItem.js b/packages/line/src/SlicesItem.js index fb01ca26c3..426ff8c54f 100644 --- a/packages/line/src/SlicesItem.js +++ b/packages/line/src/SlicesItem.js @@ -1,11 +1,3 @@ -/* - * 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 { createElement, memo, useCallback } from 'react' import PropTypes from 'prop-types' import { useTooltip } from '@nivo/tooltip' diff --git a/packages/line/src/hooks.js b/packages/line/src/hooks.js index 93e6d0fa3e..1e50851d6e 100644 --- a/packages/line/src/hooks.js +++ b/packages/line/src/hooks.js @@ -1,11 +1,3 @@ -/* - * 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 { useCallback, useMemo, useState } from 'react' import { area, line } from 'd3-shape' import { curveFromProp, useTheme, useValueFormatter } from '@nivo/core' diff --git a/packages/line/src/index.js b/packages/line/src/index.js index bae4590d2b..59b9f7f9b0 100644 --- a/packages/line/src/index.js +++ b/packages/line/src/index.js @@ -1,11 +1,3 @@ -/* - * 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. - */ export { default as Line } from './Line' export { default as ResponsiveLine } from './ResponsiveLine' export { default as LineCanvas } from './LineCanvas' diff --git a/packages/line/src/props.js b/packages/line/src/props.js index b2eeaa9d75..8a9bffb669 100644 --- a/packages/line/src/props.js +++ b/packages/line/src/props.js @@ -1,11 +1,3 @@ -/* - * 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 PropTypes from 'prop-types' import { lineCurvePropType, blendModePropType, motionPropTypes, defsPropTypes } from '@nivo/core' import { ordinalColorsPropType } from '@nivo/colors' diff --git a/packages/line/stories/LineCanvas.stories.js b/packages/line/stories/LineCanvas.stories.js index 695c2d0340..f8187e6e2b 100644 --- a/packages/line/stories/LineCanvas.stories.js +++ b/packages/line/stories/LineCanvas.stories.js @@ -1,11 +1,3 @@ -/* - * 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 { useRef } from 'react' import { storiesOf } from '@storybook/react' import { withKnobs, boolean, button } from '@storybook/addon-knobs' diff --git a/packages/line/stories/ResponsiveLineCanvas.stories.js b/packages/line/stories/ResponsiveLineCanvas.stories.js index 8df4f1649f..bd03a82c9c 100644 --- a/packages/line/stories/ResponsiveLineCanvas.stories.js +++ b/packages/line/stories/ResponsiveLineCanvas.stories.js @@ -1,11 +1,3 @@ -/* - * 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 { useRef } from 'react' import { storiesOf } from '@storybook/react' import { withKnobs, boolean, button } from '@storybook/addon-knobs' diff --git a/packages/line/stories/line.stories.js b/packages/line/stories/line.stories.js index b0104b9196..3205104d38 100644 --- a/packages/line/stories/line.stories.js +++ b/packages/line/stories/line.stories.js @@ -1,11 +1,3 @@ -/* - * 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, useState, useEffect } from 'react' import range from 'lodash/range' import last from 'lodash/last' From 4d032c98795e4745c35c5b9b4c46eba53eab4ddc Mon Sep 17 00:00:00 2001 From: plouc Date: Sat, 19 Feb 2022 06:59:18 +0900 Subject: [PATCH 2/3] feat(line): add support for TypeScript build --- packages/line/index.d.ts | 231 ------------------ packages/line/package.json | 5 +- packages/line/src/{Areas.js => Areas.tsx} | 0 packages/line/src/{Line.js => Line.tsx} | 0 .../src/{LineCanvas.js => LineCanvas.tsx} | 0 packages/line/src/{Lines.js => Lines.tsx} | 0 .../line/src/{LinesItem.js => LinesItem.tsx} | 0 packages/line/src/{Mesh.js => Mesh.tsx} | 0 .../src/{PointTooltip.js => PointTooltip.tsx} | 0 packages/line/src/{Points.js => Points.tsx} | 0 .../{ResponsiveLine.js => ResponsiveLine.tsx} | 0 ...LineCanvas.js => ResponsiveLineCanvas.tsx} | 0 .../src/{SliceTooltip.js => SliceTooltip.tsx} | 0 packages/line/src/{Slices.js => Slices.tsx} | 0 .../src/{SlicesItem.js => SlicesItem.tsx} | 0 packages/line/src/{hooks.js => hooks.ts} | 0 packages/line/src/{index.js => index.ts} | 0 packages/line/src/{props.js => props.tsx} | 0 packages/line/tsconfig.json | 8 + tsconfig.monorepo.json | 1 + 20 files changed, 12 insertions(+), 233 deletions(-) delete mode 100644 packages/line/index.d.ts rename packages/line/src/{Areas.js => Areas.tsx} (100%) rename packages/line/src/{Line.js => Line.tsx} (100%) rename packages/line/src/{LineCanvas.js => LineCanvas.tsx} (100%) rename packages/line/src/{Lines.js => Lines.tsx} (100%) rename packages/line/src/{LinesItem.js => LinesItem.tsx} (100%) rename packages/line/src/{Mesh.js => Mesh.tsx} (100%) rename packages/line/src/{PointTooltip.js => PointTooltip.tsx} (100%) rename packages/line/src/{Points.js => Points.tsx} (100%) rename packages/line/src/{ResponsiveLine.js => ResponsiveLine.tsx} (100%) rename packages/line/src/{ResponsiveLineCanvas.js => ResponsiveLineCanvas.tsx} (100%) rename packages/line/src/{SliceTooltip.js => SliceTooltip.tsx} (100%) rename packages/line/src/{Slices.js => Slices.tsx} (100%) rename packages/line/src/{SlicesItem.js => SlicesItem.tsx} (100%) rename packages/line/src/{hooks.js => hooks.ts} (100%) rename packages/line/src/{index.js => index.ts} (100%) rename packages/line/src/{props.js => props.tsx} (100%) create mode 100644 packages/line/tsconfig.json diff --git a/packages/line/index.d.ts b/packages/line/index.d.ts deleted file mode 100644 index 694775dd70..0000000000 --- a/packages/line/index.d.ts +++ /dev/null @@ -1,231 +0,0 @@ -/* - * 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 * as React from 'react' -import { - Dimensions, - Box, - Theme, - ModernMotionProps, - CartesianMarkerProps, - SvgDefsAndFill, - ValueFormat, - DatumValue as CoreDatumValue, -} from '@nivo/core' -import { OrdinalColorScaleConfig } from '@nivo/colors' -import { LegendProps } from '@nivo/legends' -import { ScaleSpec, Scale, TicksSpec } from '@nivo/scales' -import { AxisProps } from '@nivo/axes' -import { CrosshairType } from '@nivo/tooltip' -import { Line as D3Line } from 'd3-shape' - -type Omit = Pick> - -declare module '@nivo/line' { - export type DatumValue = CoreDatumValue - - export interface Datum { - x?: DatumValue | null - y?: DatumValue | null - [key: string]: any - } - export interface ComputedDatum { - data: Datum - position: { - x: number - y: number - } - } - - export interface Serie { - id: string | number - data: Datum[] - [key: string]: any - } - export interface ComputedSerie { - id: string | number - data: ComputedDatum[] - color?: string - [key: string]: any - } - - export type LineLayerType = - | 'grid' - | 'markers' - | 'axes' - | 'areas' - | 'crosshair' - | 'lines' - | 'slices' - | 'points' - | 'mesh' - | 'legends' - - export interface CustomLayerProps extends Omit { - innerHeight: number - innerWidth: number - lineGenerator: D3Line> - points: Point[] - series: ComputedSerie[] - xScale: Scale - yScale: Scale - } - - export type CustomLayer = (props: CustomLayerProps) => React.ReactNode - export type Layer = LineLayerType | CustomLayer - - export interface Point { - id: string - index: number - serieId: string | number - serieColor: string - x: number - y: number - color: string - borderColor: string - data: { - x: DatumValue - xFormatted: string | number - y: DatumValue - yFormatted: string | number - yStacked?: number - } - } - - export type AccessorFunc = (datum: Point['data']) => string - - export type PointMouseHandler = (point: Point, event: React.MouseEvent) => void - - export interface PointTooltipProps { - point: Point - } - export type PointTooltip = React.FunctionComponent - - export interface SliceTooltipProps { - axis: 'x' | 'y' - slice: { - id: DatumValue - height: number - width: number - x0: number - x: number - y0: number - y: number - points: Point[] - } - } - export type SliceTooltip = React.FunctionComponent - - export interface PointSymbolProps { - borderColor: string - borderWidth: number - color: string - datum: Datum - size: number - } - - export interface LineProps { - data: Serie[] - - xScale?: ScaleSpec - xFormat?: ValueFormat - yScale?: ScaleSpec - yFormat?: ValueFormat - - layers?: Layer[] - - margin?: Box - - curve?: - | 'basis' - | 'cardinal' - | 'catmullRom' - | 'linear' - | 'monotoneX' - | 'monotoneY' - | 'natural' - | 'step' - | 'stepAfter' - | 'stepBefore' - - lineWidth?: number - - colors?: OrdinalColorScaleConfig - theme?: Theme - - axisTop?: AxisProps | null - axisRight?: AxisProps | null - axisBottom?: AxisProps | null - axisLeft?: AxisProps | null - - enableGridX?: boolean - gridXValues?: TicksSpec - enableGridY?: boolean - gridYValues?: TicksSpec - - enablePoints?: boolean - pointSymbol?: (props: Readonly) => React.ReactNode - pointSize?: number - pointColor?: any - pointBorderWidth?: number - pointBorderColor?: any - - enableArea?: boolean - areaOpacity?: number - areaBaselineValue?: DatumValue - - markers?: CartesianMarkerProps[] - - isInteractive?: boolean - onMouseEnter?: PointMouseHandler - onMouseMove?: PointMouseHandler - onMouseLeave?: PointMouseHandler - onClick?: PointMouseHandler - - debugMesh?: boolean - - enableSlices?: 'x' | 'y' | false - debugSlices?: boolean - sliceTooltip?: SliceTooltip - - tooltipFormat?: ValueFormat - tooltip?: PointTooltip - - enableCrosshair?: boolean - crosshairType?: CrosshairType - - legends?: LegendProps[] - } - - export interface LineSvgProps extends LineProps, ModernMotionProps, SvgDefsAndFill { - enablePointLabel?: boolean - pointLabel?: string | AccessorFunc - pointLabelYOffset?: number - areaBlendMode?: string - role?: string - useMesh?: boolean - } - - export class Line extends React.Component {} - export class ResponsiveLine extends React.Component {} - - export interface CustomCanvasLayerProps extends CustomLayerProps { - ctx: CanvasRenderingContext2D - } - - export type CustomCanvasLayer = (props: CustomCanvasLayerProps) => void - export type CanvasLayer = LineLayerType | CustomCanvasLayer - - export interface LineCanvasProps extends Omit { - pixelRatio?: number - layers?: CanvasLayer[] - } - - export class LineCanvas extends React.Component {} - export class ResponsiveLineCanvas extends React.Component {} -} diff --git a/packages/line/package.json b/packages/line/package.json index e184091fa2..816942bc4d 100644 --- a/packages/line/package.json +++ b/packages/line/package.json @@ -21,11 +21,12 @@ ], "main": "./dist/nivo-line.cjs.js", "module": "./dist/nivo-line.es.js", + "typings": "./dist/types/index.d.ts", "files": [ "README.md", "LICENSE.md", - "index.d.ts", - "dist/" + "dist/", + "!dist/tsconfig.tsbuildinfo" ], "dependencies": { "@nivo/annotations": "0.79.1", diff --git a/packages/line/src/Areas.js b/packages/line/src/Areas.tsx similarity index 100% rename from packages/line/src/Areas.js rename to packages/line/src/Areas.tsx diff --git a/packages/line/src/Line.js b/packages/line/src/Line.tsx similarity index 100% rename from packages/line/src/Line.js rename to packages/line/src/Line.tsx diff --git a/packages/line/src/LineCanvas.js b/packages/line/src/LineCanvas.tsx similarity index 100% rename from packages/line/src/LineCanvas.js rename to packages/line/src/LineCanvas.tsx diff --git a/packages/line/src/Lines.js b/packages/line/src/Lines.tsx similarity index 100% rename from packages/line/src/Lines.js rename to packages/line/src/Lines.tsx diff --git a/packages/line/src/LinesItem.js b/packages/line/src/LinesItem.tsx similarity index 100% rename from packages/line/src/LinesItem.js rename to packages/line/src/LinesItem.tsx diff --git a/packages/line/src/Mesh.js b/packages/line/src/Mesh.tsx similarity index 100% rename from packages/line/src/Mesh.js rename to packages/line/src/Mesh.tsx diff --git a/packages/line/src/PointTooltip.js b/packages/line/src/PointTooltip.tsx similarity index 100% rename from packages/line/src/PointTooltip.js rename to packages/line/src/PointTooltip.tsx diff --git a/packages/line/src/Points.js b/packages/line/src/Points.tsx similarity index 100% rename from packages/line/src/Points.js rename to packages/line/src/Points.tsx diff --git a/packages/line/src/ResponsiveLine.js b/packages/line/src/ResponsiveLine.tsx similarity index 100% rename from packages/line/src/ResponsiveLine.js rename to packages/line/src/ResponsiveLine.tsx diff --git a/packages/line/src/ResponsiveLineCanvas.js b/packages/line/src/ResponsiveLineCanvas.tsx similarity index 100% rename from packages/line/src/ResponsiveLineCanvas.js rename to packages/line/src/ResponsiveLineCanvas.tsx diff --git a/packages/line/src/SliceTooltip.js b/packages/line/src/SliceTooltip.tsx similarity index 100% rename from packages/line/src/SliceTooltip.js rename to packages/line/src/SliceTooltip.tsx diff --git a/packages/line/src/Slices.js b/packages/line/src/Slices.tsx similarity index 100% rename from packages/line/src/Slices.js rename to packages/line/src/Slices.tsx diff --git a/packages/line/src/SlicesItem.js b/packages/line/src/SlicesItem.tsx similarity index 100% rename from packages/line/src/SlicesItem.js rename to packages/line/src/SlicesItem.tsx diff --git a/packages/line/src/hooks.js b/packages/line/src/hooks.ts similarity index 100% rename from packages/line/src/hooks.js rename to packages/line/src/hooks.ts diff --git a/packages/line/src/index.js b/packages/line/src/index.ts similarity index 100% rename from packages/line/src/index.js rename to packages/line/src/index.ts diff --git a/packages/line/src/props.js b/packages/line/src/props.tsx similarity index 100% rename from packages/line/src/props.js rename to packages/line/src/props.tsx diff --git a/packages/line/tsconfig.json b/packages/line/tsconfig.json new file mode 100644 index 0000000000..855b4b2b74 --- /dev/null +++ b/packages/line/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.types.json", + "compilerOptions": { + "outDir": "./dist/types", + "rootDir": "./src" + }, + "include": ["src/**/*"] +} diff --git a/tsconfig.monorepo.json b/tsconfig.monorepo.json index 99343d876a..134504bc7d 100644 --- a/tsconfig.monorepo.json +++ b/tsconfig.monorepo.json @@ -28,6 +28,7 @@ { "path": "./packages/circle-packing" }, { "path": "./packages/funnel" }, { "path": "./packages/heatmap" }, + { "path": "./packages/line" }, { "path": "./packages/marimekko" }, { "path": "./packages/network" }, { "path": "./packages/pie" }, From 52315c4a49032b3c1a6a11a0221e18f5e4d6f304 Mon Sep 17 00:00:00 2001 From: plouc Date: Wed, 23 Feb 2022 07:29:19 +0900 Subject: [PATCH 3/3] feat(line): init migration of the SVG version --- packages/line/__old_index.d.ts | 223 + packages/line/src/Areas.tsx | 55 +- packages/line/src/Line.tsx | 300 +- packages/line/src/Lines.tsx | 76 +- packages/line/src/LinesItem.tsx | 30 +- packages/line/src/Mesh.tsx | 33 +- packages/line/src/PointTooltip.tsx | 36 +- packages/line/src/Points.tsx | 24 +- packages/line/src/ResponsiveLine.tsx | 16 +- packages/line/src/ResponsiveLineCanvas.tsx | 15 +- packages/line/src/SliceTooltip.tsx | 14 +- packages/line/src/Slices.tsx | 70 +- packages/line/src/SlicesItem.tsx | 30 +- packages/line/src/defaults.ts | 108 + packages/line/src/hooks.ts | 203 +- packages/line/src/index.ts | 7 +- packages/line/src/props.tsx | 6 +- packages/line/src/types.ts | 209 + .../{line.stories.js => Line.stories.tsx} | 17 +- .../tests/{Line.test.js => Line.test.tsx} | 128 +- .../tests/__snapshots__/Line.test.js.snap | 9565 ----------------- 21 files changed, 1186 insertions(+), 9979 deletions(-) create mode 100644 packages/line/__old_index.d.ts create mode 100644 packages/line/src/defaults.ts create mode 100644 packages/line/src/types.ts rename packages/line/stories/{line.stories.js => Line.stories.tsx} (99%) rename packages/line/tests/{Line.test.js => Line.test.tsx} (56%) delete mode 100644 packages/line/tests/__snapshots__/Line.test.js.snap diff --git a/packages/line/__old_index.d.ts b/packages/line/__old_index.d.ts new file mode 100644 index 0000000000..9b0c465890 --- /dev/null +++ b/packages/line/__old_index.d.ts @@ -0,0 +1,223 @@ +import * as React from 'react' +import { + Dimensions, + Box, + Theme, + ModernMotionProps, + CartesianMarkerProps, + SvgDefsAndFill, + ValueFormat, + DatumValue as CoreDatumValue, +} from '@nivo/core' +import { OrdinalColorScaleConfig } from '@nivo/colors' +import { LegendProps } from '@nivo/legends' +import { ScaleSpec, Scale, TicksSpec } from '@nivo/scales' +import { AxisProps } from '@nivo/axes' +import { CrosshairType } from '@nivo/tooltip' +import { Line as D3Line } from 'd3-shape' + +type Omit = Pick> + +declare module '@nivo/line' { + export type DatumValue = CoreDatumValue + + export interface Datum { + x?: DatumValue | null + y?: DatumValue | null + [key: string]: any + } + export interface ComputedDatum { + data: Datum + position: { + x: number + y: number + } + } + + export interface Serie { + id: string | number + data: Datum[] + [key: string]: any + } + export interface ComputedSerie { + id: string | number + data: ComputedDatum[] + color?: string + [key: string]: any + } + + export type LineLayerType = + | 'grid' + | 'markers' + | 'axes' + | 'areas' + | 'crosshair' + | 'lines' + | 'slices' + | 'points' + | 'mesh' + | 'legends' + + export interface CustomLayerProps extends Omit { + innerHeight: number + innerWidth: number + lineGenerator: D3Line> + points: Point[] + series: ComputedSerie[] + xScale: Scale + yScale: Scale + } + + export type CustomLayer = (props: CustomLayerProps) => React.ReactNode + export type Layer = LineLayerType | CustomLayer + + export interface Point { + id: string + index: number + serieId: string | number + serieColor: string + x: number + y: number + color: string + borderColor: string + data: { + x: DatumValue + xFormatted: string | number + y: DatumValue + yFormatted: string | number + yStacked?: number + } + } + + export type AccessorFunc = (datum: Point['data']) => string + + export type PointMouseHandler = (point: Point, event: React.MouseEvent) => void + + export interface PointTooltipProps { + point: Point + } + export type PointTooltip = React.FunctionComponent + + export interface SliceTooltipProps { + axis: 'x' | 'y' + slice: { + id: DatumValue + height: number + width: number + x0: number + x: number + y0: number + y: number + points: Point[] + } + } + export type SliceTooltip = React.FunctionComponent + + export interface PointSymbolProps { + borderColor: string + borderWidth: number + color: string + datum: Datum + size: number + } + + export interface LineProps { + data: Serie[] + + xScale?: ScaleSpec + xFormat?: ValueFormat + yScale?: ScaleSpec + yFormat?: ValueFormat + + layers?: Layer[] + + margin?: Box + + curve?: + | 'basis' + | 'cardinal' + | 'catmullRom' + | 'linear' + | 'monotoneX' + | 'monotoneY' + | 'natural' + | 'step' + | 'stepAfter' + | 'stepBefore' + + lineWidth?: number + + colors?: OrdinalColorScaleConfig + theme?: Theme + + axisTop?: AxisProps | null + axisRight?: AxisProps | null + axisBottom?: AxisProps | null + axisLeft?: AxisProps | null + + enableGridX?: boolean + gridXValues?: TicksSpec + enableGridY?: boolean + gridYValues?: TicksSpec + + enablePoints?: boolean + pointSymbol?: (props: Readonly) => React.ReactNode + pointSize?: number + pointColor?: any + pointBorderWidth?: number + pointBorderColor?: any + + enableArea?: boolean + areaOpacity?: number + areaBaselineValue?: DatumValue + + markers?: CartesianMarkerProps[] + + isInteractive?: boolean + onMouseEnter?: PointMouseHandler + onMouseMove?: PointMouseHandler + onMouseLeave?: PointMouseHandler + onClick?: PointMouseHandler + + debugMesh?: boolean + + enableSlices?: 'x' | 'y' | false + debugSlices?: boolean + sliceTooltip?: SliceTooltip + + tooltipFormat?: ValueFormat + tooltip?: PointTooltip + + enableCrosshair?: boolean + crosshairType?: CrosshairType + + legends?: LegendProps[] + } + + export interface LineSvgProps extends LineProps, ModernMotionProps, SvgDefsAndFill { + enablePointLabel?: boolean + pointLabel?: string | AccessorFunc + pointLabelYOffset?: number + areaBlendMode?: string + role?: string + useMesh?: boolean + } + + export class Line extends React.Component {} + export class ResponsiveLine extends React.Component {} + + export interface CustomCanvasLayerProps extends CustomLayerProps { + ctx: CanvasRenderingContext2D + } + + export type CustomCanvasLayer = (props: CustomCanvasLayerProps) => void + export type CanvasLayer = LineLayerType | CustomCanvasLayer + + export interface LineCanvasProps extends Omit { + pixelRatio?: number + layers?: CanvasLayer[] + } + + export class LineCanvas extends React.Component {} + export class ResponsiveLineCanvas extends React.Component {} +} diff --git a/packages/line/src/Areas.tsx b/packages/line/src/Areas.tsx index aa7de94555..40ffab76e9 100644 --- a/packages/line/src/Areas.tsx +++ b/packages/line/src/Areas.tsx @@ -1,9 +1,21 @@ import { memo } from 'react' -import PropTypes from 'prop-types' import { useSpring, animated } from '@react-spring/web' -import { useAnimatedPath, useMotionConfig, blendModePropType } from '@nivo/core' +import { useAnimatedPath, useMotionConfig, CssMixBlendMode } from '@nivo/core' +import { AreaGenerator, LineDatum } from './types' -const AreaPath = ({ areaBlendMode, areaOpacity, color, fill, path }) => { +const AreaPath = ({ + blendMode, + opacity, + color, + fill, + path, +}: { + blendMode: CssMixBlendMode + opacity: number + color: string + fill?: string + path: string +}) => { const { animate, config: springConfig } = useMotionConfig() const animatedPath = useAnimatedPath(path) @@ -17,24 +29,26 @@ const AreaPath = ({ areaBlendMode, areaOpacity, color, fill, path }) => { ) } -AreaPath.propTypes = { - areaBlendMode: blendModePropType.isRequired, - areaOpacity: PropTypes.number.isRequired, - color: PropTypes.string, - fill: PropTypes.string, - path: PropTypes.string.isRequired, -} - -const Areas = ({ areaGenerator, areaOpacity, areaBlendMode, lines }) => { +const NonMemoizedAreas = ({ + areaGenerator, + areaOpacity, + areaBlendMode, + lines, +}: { + areaGenerator: AreaGenerator + areaOpacity: number + areaBlendMode: CssMixBlendMode + lines: any[] +}) => { const computedLines = lines.slice(0).reverse() return ( @@ -43,18 +57,13 @@ const Areas = ({ areaGenerator, areaOpacity, areaBlendMode, lines }) => { d.position))} - {...{ areaOpacity, areaBlendMode, ...line }} + opacity={areaOpacity} + blendMode={areaBlendMode} + {...line} /> ))} ) } -Areas.propTypes = { - areaGenerator: PropTypes.func.isRequired, - areaOpacity: PropTypes.number.isRequired, - areaBlendMode: blendModePropType.isRequired, - lines: PropTypes.arrayOf(PropTypes.object).isRequired, -} - -export default memo(Areas) +export const Areas = memo(NonMemoizedAreas) as typeof NonMemoizedAreas diff --git a/packages/line/src/Line.tsx b/packages/line/src/Line.tsx index 71c52085ce..4299aeef26 100644 --- a/packages/line/src/Line.tsx +++ b/packages/line/src/Line.tsx @@ -1,9 +1,10 @@ -import { Fragment, useState } from 'react' +import { Fragment, ReactNode, useState } from 'react' import { - bindDefs, - withContainer, + Container, useDimensions, useTheme, + // @ts-ignore + bindDefs, SvgWrapper, CartesianMarkers, } from '@nivo/core' @@ -11,82 +12,88 @@ import { useInheritedColor } from '@nivo/colors' import { Axes, Grid } from '@nivo/axes' import { BoxLegendSvg } from '@nivo/legends' import { Crosshair } from '@nivo/tooltip' +import { DefaultLineDatum, LineDatum, LineLayerId, LineSvgProps } from './types' +import { svgDefaultProps } from './defaults' import { useLine } from './hooks' -import { LinePropTypes, LineDefaultProps } from './props' -import Areas from './Areas' -import Lines from './Lines' -import Slices from './Slices' -import Points from './Points' -import Mesh from './Mesh' - -const Line = props => { +import { Areas } from './Areas' +import { Lines } from './Lines' +import { Slices } from './Slices' +import { Points } from './Points' +import { Mesh } from './Mesh' + +type InnerLineProps = Omit< + LineSvgProps, + 'animate' | 'motionConfig' | 'renderWrapper' | 'theme' +> + +const InnerLine = ( + props: InnerLineProps +) => { const { data, - xScale: xScaleSpec, + xScale: xScaleSpec = svgDefaultProps.xScale, xFormat, - yScale: yScaleSpec, + yScale: yScaleSpec = svgDefaultProps.yScale, yFormat, - layers, - curve, - areaBaselineValue, + layers = svgDefaultProps.layers, - colors, + colors = svgDefaultProps.colors, margin: partialMargin, width, height, - axisTop, - axisRight, - axisBottom, - axisLeft, - enableGridX, - enableGridY, + enableGridX = svgDefaultProps.enableGridX, gridXValues, + enableGridY = svgDefaultProps.enableGridY, gridYValues, + axisTop = svgDefaultProps.axisTop, + axisRight = svgDefaultProps.axisRight, + axisBottom = svgDefaultProps.axisBottom, + axisLeft = svgDefaultProps.axisLeft, - lineWidth, - enableArea, - areaOpacity, - areaBlendMode, + curve = svgDefaultProps.curve, + lineWidth = svgDefaultProps.lineWidth, + enableArea = svgDefaultProps.enableArea, + areaBaselineValue = svgDefaultProps.areaBaselineValue, + areaOpacity = svgDefaultProps.areaOpacity, + areaBlendMode = svgDefaultProps.areaBlendMode, - enablePoints, + enablePoints = svgDefaultProps.enablePoints, pointSymbol, - pointSize, + pointSize = svgDefaultProps.pointSize, pointColor, - pointBorderWidth, + pointBorderWidth = svgDefaultProps.pointBorderWidth, pointBorderColor, - enablePointLabel, + enablePointLabel = svgDefaultProps.enablePointLabel, pointLabel, pointLabelYOffset, - defs, - fill, - - markers, - - legends, + defs = svgDefaultProps.defs, + fill = svgDefaultProps.fill, - isInteractive, + markers = svgDefaultProps.markers, - useMesh, - debugMesh, + legends = svgDefaultProps.legends, + isInteractive = svgDefaultProps.isInteractive, + useMesh = svgDefaultProps.useMesh, + debugMesh = svgDefaultProps.debugMesh, + enableSlices = svgDefaultProps.enableSlices, + debugSlices = svgDefaultProps.debugSlices, + sliceTooltip = svgDefaultProps.sliceTooltip, + enableCrosshair = svgDefaultProps.enableCrosshair, + crosshairType = svgDefaultProps.crosshairType, onMouseEnter, onMouseMove, onMouseLeave, onClick, - - tooltip, - - enableSlices, - debugSlices, - sliceTooltip, - - enableCrosshair, - crosshairType, + tooltip = svgDefaultProps.tooltip, role, + ariaLabel, + ariaLabelledBy, + ariaDescribedBy, } = props const { margin, innerWidth, innerHeight, outerWidth, outerHeight } = useDimensions( @@ -104,8 +111,12 @@ const Line = props => { xScale, yScale, slices, + currentSlice, + setCurrentSlice, points, - } = useLine({ + currentPoint, + setCurrentPoint, + } = useLine({ data, xScale: xScaleSpec, xFormat, @@ -121,15 +132,31 @@ const Line = props => { enableSlices, }) + series.forEach(serie => { + console.log(serie) + serie.data.forEach(datum => { + console.log(datum) + }) + }) + const theme = useTheme() - const getPointColor = useInheritedColor(pointColor, theme) const getPointBorderColor = useInheritedColor(pointBorderColor, theme) - const [currentPoint, setCurrentPoint] = useState(null) - const [currentSlice, setCurrentSlice] = useState(null) + const layerById: Record = { + grid: null, + markers: null, + axes: null, + areas: null, + crosshair: null, + lines: null, + slices: null, + points: null, + mesh: null, + legends: null, + } - const layerById = { - grid: ( + if (layers.includes('grid')) { + layerById.grid = ( { xValues={gridXValues} yValues={gridYValues} /> - ), - markers: ( + ) + } + + if (markers.length > 0 && layers.includes('markers')) { + layerById.markers = ( { yScale={yScale} theme={theme} /> - ), - axes: ( + ) + } + + if (layers.includes('axes')) { + layerById.axes = ( { bottom={axisBottom} left={axisLeft} /> - ), - areas: null, - lines: ( - - ), - slices: null, - points: null, - crosshair: null, - mesh: null, - legends: legends.map((legend, i) => ( - - )), + ) } - const boundDefs = bindDefs(defs, series, fill) - - if (enableArea) { + if (layers.includes('areas') && enableArea) { layerById.areas = ( - key="areas" areaGenerator={areaGenerator} areaOpacity={areaOpacity} @@ -201,14 +213,24 @@ const Line = props => { ) } - if (isInteractive && enableSlices !== false) { + if (layers.includes('lines')) { + layerById.lines = ( + + key="lines" + lines={series} + lineGenerator={lineGenerator} + lineWidth={lineWidth} + /> + ) + } + + if (isInteractive && enableSlices && layers.includes('slices')) { layerById.slices = ( { ) } - if (enablePoints) { + if (enablePoints && layers.includes('points')) { layerById.points = ( - key="points" points={points} symbol={pointSymbol} size={pointSize} - color={getPointColor} borderWidth={pointBorderWidth} borderColor={getPointBorderColor} enableLabel={enablePointLabel} @@ -233,9 +254,50 @@ const Line = props => { ) } + if (isInteractive && useMesh && !enableSlices && layers.includes('mesh')) { + layerById.mesh = ( + + key="mesh" + points={points} + width={innerWidth} + height={innerHeight} + margin={margin} + setCurrent={setCurrentPoint} + onMouseEnter={onMouseEnter} + onMouseMove={onMouseMove} + onMouseLeave={onMouseLeave} + onClick={onClick} + tooltip={tooltip} + debug={debugMesh} + /> + ) + } + + if (layers.includes('legends') && legends.length > 0) { + layerById.legends = ( + + {legends.map((legend, legendIndex) => ( + + ))} + + ) + } + + const ___layerById = {} + + const boundDefs = bindDefs(defs, series, fill) + if (isInteractive && enableCrosshair) { if (currentPoint !== null) { - layerById.crosshair = ( + ___layerById.crosshair = ( { ) } if (currentSlice !== null) { - layerById.crosshair = ( + ___layerById.crosshair = ( { } } - if (isInteractive && useMesh && enableSlices === false) { - layerById.mesh = ( - - ) - } - return ( { height={outerHeight} margin={margin} role={role} + ariaLabel={ariaLabel} + ariaLabelledBy={ariaLabelledBy} + ariaDescribedBy={ariaDescribedBy} > - {layers.map((layer, i) => { + {layers.map((layer, layerIndex) => { if (typeof layer === 'function') { return ( - + {layer({ ...props, innerWidth, @@ -312,13 +357,32 @@ const Line = props => { ) } - return layerById[layer] + return layerById?.[layer] ?? null })} ) } -Line.propTypes = LinePropTypes -Line.defaultProps = LineDefaultProps - -export default withContainer(Line) +export const Line = < + Datum extends LineDatum = DefaultLineDatum, + ExtraProps extends object = Record +>({ + isInteractive = svgDefaultProps.isInteractive, + animate = svgDefaultProps.animate, + motionConfig = svgDefaultProps.motionConfig, + theme, + renderWrapper, + ...otherProps +}: LineSvgProps) => ( + + isInteractive={isInteractive} {...otherProps} /> + +) diff --git a/packages/line/src/Lines.tsx b/packages/line/src/Lines.tsx index 04582a8a8c..2c91d3ad22 100644 --- a/packages/line/src/Lines.tsx +++ b/packages/line/src/Lines.tsx @@ -1,52 +1,30 @@ import { memo } from 'react' -import PropTypes from 'prop-types' -import LinesItem from './LinesItem' +import { LineDatum, LineGenerator } from './types' +import { LinesItem } from './LinesItem' -const Lines = ({ lines, lineGenerator, lineWidth }) => { - return lines - .slice(0) - .reverse() - .map(({ id, data, color }) => ( - d.position)} - lineGenerator={lineGenerator} - color={color} - thickness={lineWidth} - /> - )) -} +const NonMemoizedLines = ({ + lines, + lineGenerator, + lineWidth, +}: { + lines: any[] + lineGenerator: LineGenerator + lineWidth: number +}) => ( + <> + {lines + .slice(0) + .reverse() + .map(({ id, data, color }) => ( + + key={id} + points={data.map(d => d.position)} + lineGenerator={lineGenerator} + color={color} + thickness={lineWidth} + /> + ))} + +) -Lines.propTypes = { - lines: PropTypes.arrayOf( - PropTypes.shape({ - id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, - color: PropTypes.string.isRequired, - data: PropTypes.arrayOf( - PropTypes.shape({ - data: PropTypes.shape({ - x: PropTypes.oneOfType([ - PropTypes.string, - PropTypes.number, - PropTypes.instanceOf(Date), - ]), - y: PropTypes.oneOfType([ - PropTypes.string, - PropTypes.number, - PropTypes.instanceOf(Date), - ]), - }).isRequired, - position: PropTypes.shape({ - x: PropTypes.number, - y: PropTypes.number, - }).isRequired, - }) - ).isRequired, - }) - ).isRequired, - lineWidth: PropTypes.number.isRequired, - lineGenerator: PropTypes.func.isRequired, -} - -export default memo(Lines) +export const Lines = memo(NonMemoizedLines) as typeof NonMemoizedLines diff --git a/packages/line/src/LinesItem.tsx b/packages/line/src/LinesItem.tsx index e7b698293c..bedc3468d1 100644 --- a/packages/line/src/LinesItem.tsx +++ b/packages/line/src/LinesItem.tsx @@ -1,25 +1,23 @@ import { memo, useMemo } from 'react' -import PropTypes from 'prop-types' import { animated } from '@react-spring/web' import { useAnimatedPath } from '@nivo/core' +import { LineDatum, LineGenerator, LinePointDatum } from './types' -const LinesItem = ({ lineGenerator, points, color, thickness }) => { +const NonMemoizedLinesItem = ({ + lineGenerator, + points, + color, + thickness, +}: { + lineGenerator: LineGenerator + points: LinePointDatum[] + color: string + thickness: number +}) => { const path = useMemo(() => lineGenerator(points), [lineGenerator, points]) - const animatedPath = useAnimatedPath(path) + const animatedPath = useAnimatedPath(path!) return } -LinesItem.propTypes = { - points: PropTypes.arrayOf( - PropTypes.shape({ - x: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), - y: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), - }) - ), - lineGenerator: PropTypes.func.isRequired, - color: PropTypes.string.isRequired, - thickness: PropTypes.number.isRequired, -} - -export default memo(LinesItem) +export const LinesItem = memo(NonMemoizedLinesItem) as typeof NonMemoizedLinesItem diff --git a/packages/line/src/Mesh.tsx b/packages/line/src/Mesh.tsx index ecb827aeb3..3139c09cb2 100644 --- a/packages/line/src/Mesh.tsx +++ b/packages/line/src/Mesh.tsx @@ -1,9 +1,10 @@ import { createElement, memo, useCallback } from 'react' -import PropTypes from 'prop-types' +import { Margin } from '@nivo/core' import { useTooltip } from '@nivo/tooltip' import { Mesh as BaseMesh } from '@nivo/voronoi' +import { LinePointDatum, LineDatum, LineCommonProps } from './types' -const Mesh = ({ +const NonMemoizedMesh = ({ points, width, height, @@ -15,6 +16,18 @@ const Mesh = ({ onClick, tooltip, debug, +}: { + points: LinePointDatum[] + width: number + height: number + margin: Margin + setCurrent: (point: LinePointDatum | null) => void + onMouseEnter?: LineCommonProps['onMouseEnter'] + onMouseMove?: LineCommonProps['onMouseMove'] + onMouseLeave?: LineCommonProps['onMouseLeave'] + onClick?: LineCommonProps['onClick'] + tooltip: LineCommonProps['tooltip'] + debug: LineCommonProps['debugMesh'] }) => { const { showTooltipAt, hideTooltip } = useTooltip() @@ -74,18 +87,4 @@ const Mesh = ({ ) } -Mesh.propTypes = { - points: PropTypes.arrayOf(PropTypes.object).isRequired, - width: PropTypes.number.isRequired, - height: PropTypes.number.isRequired, - margin: PropTypes.object.isRequired, - setCurrent: PropTypes.func.isRequired, - onMouseEnter: PropTypes.func, - onMouseMove: PropTypes.func, - onMouseLeave: PropTypes.func, - onClick: PropTypes.func, - tooltip: PropTypes.oneOfType([PropTypes.func, PropTypes.object]).isRequired, - debug: PropTypes.bool.isRequired, -} - -export default memo(Mesh) +export const Mesh = memo(NonMemoizedMesh) as typeof NonMemoizedMesh diff --git a/packages/line/src/PointTooltip.tsx b/packages/line/src/PointTooltip.tsx index bd5104606f..e9dd2bb0b3 100644 --- a/packages/line/src/PointTooltip.tsx +++ b/packages/line/src/PointTooltip.tsx @@ -1,24 +1,24 @@ import { memo } from 'react' -import PropTypes from 'prop-types' import { BasicTooltip } from '@nivo/tooltip' +import { LineDatum, LinePointDatum } from './types' -const LinePointTooltip = ({ point }) => { - return ( - - x: {point.data.xFormatted}, y:{' '} - {point.data.yFormatted} - - } - enableChip={true} - color={point.serieColor} - /> - ) +interface LinePointTooltipProps { + point: LinePointDatum } -LinePointTooltip.propTypes = { - point: PropTypes.object.isRequired, -} +const NonMemoizedPointTooltip = ({ + point, +}: LinePointTooltipProps) => ( + + x: {point.data.xFormatted}, y:{' '} + {point.data.yFormatted} + + } + enableChip={true} + color={point.serieColor} + /> +) -export default memo(LinePointTooltip) +export const PointTooltip = memo(NonMemoizedPointTooltip) as typeof NonMemoizedPointTooltip diff --git a/packages/line/src/Points.tsx b/packages/line/src/Points.tsx index c6f70791cc..3c95f5ffc3 100644 --- a/packages/line/src/Points.tsx +++ b/packages/line/src/Points.tsx @@ -1,8 +1,24 @@ import { memo } from 'react' -import PropTypes from 'prop-types' import { getLabelGenerator, DotsItem, useTheme } from '@nivo/core' +import { LinePointDatum, LineDatum } from './types' -const Points = ({ points, symbol, size, borderWidth, enableLabel, label, labelYOffset }) => { +const NonMemoizedPoints = ({ + points, + symbol, + size, + borderWidth, + enableLabel, + label, + labelYOffset, +}: { + points: LinePointDatum[] + symbol: any + size: number + borderWidth: number + enableLabel: boolean + label: any + labelYOffset: number +}) => { const theme = useTheme() const getLabel = getLabelGenerator(label) @@ -46,6 +62,7 @@ const Points = ({ points, symbol, size, borderWidth, enableLabel, label, labelYO ) } +/* Points.propTypes = { points: PropTypes.arrayOf(PropTypes.object), symbol: PropTypes.func, @@ -57,5 +74,6 @@ Points.propTypes = { label: PropTypes.oneOfType([PropTypes.string, PropTypes.func]).isRequired, labelYOffset: PropTypes.number, } +*/ -export default memo(Points) +export const Points = memo(NonMemoizedPoints) as typeof NonMemoizedPoints diff --git a/packages/line/src/ResponsiveLine.tsx b/packages/line/src/ResponsiveLine.tsx index e60b0a80b4..14bf5675dd 100644 --- a/packages/line/src/ResponsiveLine.tsx +++ b/packages/line/src/ResponsiveLine.tsx @@ -1,10 +1,16 @@ import { ResponsiveWrapper } from '@nivo/core' -import Line from './Line' +import { DefaultLineDatum, LineDatum, LineSvgProps } from './types' +import { Line } from './Line' -const ResponsiveLine = props => ( +export const ResponsiveLine = < + Datum extends LineDatum = DefaultLineDatum, + ExtraProps extends object = Record +>( + props: Omit, 'height' | 'width'> +) => ( - {({ width, height }) => } + {({ width, height }) => ( + width={width} height={height} {...props} /> + )} ) - -export default ResponsiveLine diff --git a/packages/line/src/ResponsiveLineCanvas.tsx b/packages/line/src/ResponsiveLineCanvas.tsx index c1416d58b9..1ef3e63f06 100644 --- a/packages/line/src/ResponsiveLineCanvas.tsx +++ b/packages/line/src/ResponsiveLineCanvas.tsx @@ -1,11 +1,18 @@ -import { forwardRef } from 'react' import { ResponsiveWrapper } from '@nivo/core' +import { DefaultLineDatum, LineDatum, LineCanvasProps } from './types' import LineCanvas from './LineCanvas' -const ResponsiveLineCanvas = (props, ref) => ( +export const ResponsiveLineCanvas = < + Datum extends LineDatum = DefaultLineDatum, + ExtraProps extends object = Record +>( + props: Omit, 'height' | 'width'> +) => ( - {({ width, height }) => } + {({ width, height }) => ( + width={width} height={height} {...props} /> + )} ) -export default forwardRef(ResponsiveLineCanvas) +// export default forwardRef(ResponsiveLineCanvas) diff --git a/packages/line/src/SliceTooltip.tsx b/packages/line/src/SliceTooltip.tsx index 7609020c42..0fdff0a7e6 100644 --- a/packages/line/src/SliceTooltip.tsx +++ b/packages/line/src/SliceTooltip.tsx @@ -1,9 +1,12 @@ import { memo } from 'react' -import PropTypes from 'prop-types' import { useTheme } from '@nivo/core' import { Chip, TableTooltip } from '@nivo/tooltip' +import { LineDatum, SliceTooltipProps } from './types' -const SliceTooltip = ({ slice, axis }) => { +const NonMemoizedSliceTooltip = ({ + slice, + axis, +}: SliceTooltipProps) => { const theme = useTheme() const otherAxis = axis === 'x' ? 'y' : 'x' @@ -20,9 +23,4 @@ const SliceTooltip = ({ slice, axis }) => { ) } -SliceTooltip.propTypes = { - slice: PropTypes.object.isRequired, - axis: PropTypes.oneOf(['x', 'y']).isRequired, -} - -export default memo(SliceTooltip) +export const SliceTooltip = memo(NonMemoizedSliceTooltip) as typeof NonMemoizedSliceTooltip diff --git a/packages/line/src/Slices.tsx b/packages/line/src/Slices.tsx index 9bdad7792d..4e0e60cf52 100644 --- a/packages/line/src/Slices.tsx +++ b/packages/line/src/Slices.tsx @@ -1,41 +1,35 @@ import { memo } from 'react' -import PropTypes from 'prop-types' -import SlicesItem from './SlicesItem' +import { LineCommonProps, LineDatum, SliceDatum } from './types' +import { SlicesItem } from './SlicesItem' -const Slices = ({ slices, axis, debug, height, tooltip, current, setCurrent }) => { - return slices.map(slice => ( - - )) -} +const NonMemoizedSlices = ({ + slices, + axis, + debug, + tooltip, + current, + setCurrent, +}: { + slices: SliceDatum[] + axis: Exclude['enableSlices'], false> + debug: boolean + tooltip: LineCommonProps['sliceTooltip'] + current: SliceDatum | null + setCurrent: (slice: SliceDatum | null) => void +}) => ( + <> + {slices.map(slice => ( + + key={slice.id} + slice={slice} + axis={axis} + debug={debug} + tooltip={tooltip} + setCurrent={setCurrent} + isCurrent={current !== null && current.id === slice.id} + /> + ))} + +) -Slices.propTypes = { - slices: PropTypes.arrayOf( - PropTypes.shape({ - id: PropTypes.oneOfType([ - PropTypes.number, - PropTypes.string, - PropTypes.instanceOf(Date), - ]).isRequired, - x: PropTypes.number.isRequired, - y: PropTypes.number.isRequired, - points: PropTypes.arrayOf(PropTypes.object).isRequired, - }) - ).isRequired, - axis: PropTypes.oneOf(['x', 'y']).isRequired, - debug: PropTypes.bool.isRequired, - height: PropTypes.number.isRequired, - tooltip: PropTypes.oneOfType([PropTypes.func, PropTypes.object]).isRequired, - current: PropTypes.object, - setCurrent: PropTypes.func.isRequired, -} - -export default memo(Slices) +export const Slices = memo(NonMemoizedSlices) as typeof NonMemoizedSlices diff --git a/packages/line/src/SlicesItem.tsx b/packages/line/src/SlicesItem.tsx index 426ff8c54f..4c5185e6bc 100644 --- a/packages/line/src/SlicesItem.tsx +++ b/packages/line/src/SlicesItem.tsx @@ -1,8 +1,22 @@ import { createElement, memo, useCallback } from 'react' -import PropTypes from 'prop-types' import { useTooltip } from '@nivo/tooltip' +import { LineCommonProps, LineDatum, SliceAxis, SliceDatum } from './types' -const SlicesItem = ({ slice, axis, debug, tooltip, isCurrent, setCurrent }) => { +const NonMemoizedSlicesItem = ({ + slice, + axis, + debug, + tooltip, + isCurrent, + setCurrent, +}: { + slice: SliceDatum + axis: SliceAxis + debug: boolean + tooltip: LineCommonProps['sliceTooltip'] + isCurrent: boolean + setCurrent: (slice: SliceDatum | null) => void +}) => { const { showTooltipFromEvent, hideTooltip } = useTooltip() const handleMouseEnter = useCallback( @@ -43,14 +57,4 @@ const SlicesItem = ({ slice, axis, debug, tooltip, isCurrent, setCurrent }) => { ) } -SlicesItem.propTypes = { - slice: PropTypes.object.isRequired, - axis: PropTypes.oneOf(['x', 'y']).isRequired, - debug: PropTypes.bool.isRequired, - height: PropTypes.number.isRequired, - tooltip: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - isCurrent: PropTypes.bool.isRequired, - setCurrent: PropTypes.func.isRequired, -} - -export default memo(SlicesItem) +export const SlicesItem = memo(NonMemoizedSlicesItem) as typeof NonMemoizedSlicesItem diff --git a/packages/line/src/defaults.ts b/packages/line/src/defaults.ts new file mode 100644 index 0000000000..7a16820ebc --- /dev/null +++ b/packages/line/src/defaults.ts @@ -0,0 +1,108 @@ +import { DefaultLineDatum, LineCommonProps, LineLayerId } from './types' +import { SliceTooltip } from './SliceTooltip' +import { PointTooltip } from './PointTooltip' + +export const commonDefaultProps: Omit< + LineCommonProps, + | 'margin' + | 'theme' + | 'valueFormat' + | 'onClick' + | 'renderWrapper' + | 'role' + | 'ariaLabel' + | 'ariaLabelledBy' + | 'ariaDescribedBy' +> & { + layers: LineLayerId[] +} = { + layers: [ + 'grid', + 'markers', + 'axes', + 'areas', + 'crosshair', + 'lines', + 'points', + 'slices', + 'mesh', + 'legends', + ] as LineLayerId[], + + xScale: { + type: 'point', + }, + yScale: { + type: 'linear', + min: 0, + max: 'auto', + }, + + enableGridX: false, + enableGridY: false, + + curve: 'linear' as const, + lineWidth: 2, + enableArea: false, + areaBaselineValue: 0, + areaOpacity: 0.2, + areaBlendMode: 'normal' as const, + + enablePoints: true, + pointSize: 6, + pointColor: { from: 'color' }, + pointBorderWidth: 0, + pointBorderColor: { theme: 'background' }, + enablePointLabel: false, + pointLabel: 'yFormatted', + + colors: { scheme: 'nivo' }, + + opacity: 1, + activeOpacity: 1, + inactiveOpacity: 0.15, + borderWidth: 0, + borderColor: { from: 'color', modifiers: [['darker', 0.8]] }, + + enableLabels: true, + label: 'formattedValue', + + legends: [], + markers: [], + annotations: [], + + isInteractive: true, + debugMesh: false, + enableSlices: false, + debugSlices: false, + sliceTooltip: SliceTooltip, + enableCrosshair: true, + crosshairType: 'bottom-left' as const, + tooltip: PointTooltip, + + animate: true, + motionConfig: 'gentle' as const, +} + +export const svgDefaultProps = { + ...commonDefaultProps, + axisTop: {}, + axisRight: null, + axisBottom: null, + axisLeft: {}, + borderRadius: 0, + cellComponent: 'rect' as const, + defs: [], + fill: [], + useMesh: false, +} + +export const canvasDefaultProps = { + ...commonDefaultProps, + axisTop: {}, + axisRight: null, + axisBottom: null, + axisLeft: {}, + renderCell: 'rect' as const, + pixelRatio: typeof window !== 'undefined' ? window.devicePixelRatio || 1 : 1, +} diff --git a/packages/line/src/hooks.ts b/packages/line/src/hooks.ts index 1e50851d6e..eb685a17fc 100644 --- a/packages/line/src/hooks.ts +++ b/packages/line/src/hooks.ts @@ -4,63 +4,107 @@ import { curveFromProp, useTheme, useValueFormatter } from '@nivo/core' import { useOrdinalColorScale, useInheritedColor } from '@nivo/colors' import { computeXYScalesForSeries } from '@nivo/scales' import { LineDefaultProps } from './props' +import { commonDefaultProps } from './defaults' +import { + CurveInterpolation, + LineCommonProps, + LineDataProps, + LineDatum, + LinePointDatum, + SliceDatum, +} from './types' -export const useLineGenerator = ({ curve }) => { - return useMemo( +export const useLineGenerator = ({ + curve, +}: { + curve: CurveInterpolation +}) => + useMemo( () => - line() + line['position']>() .defined(d => d.x !== null && d.y !== null) .x(d => d.x) .y(d => d.y) .curve(curveFromProp(curve)), [curve] ) -} -export const useAreaGenerator = ({ curve, yScale, areaBaselineValue }) => { - return useMemo(() => { - return area() - .defined(d => d.x !== null && d.y !== null) - .x(d => d.x) - .y1(d => d.y) - .curve(curveFromProp(curve)) - .y0(yScale(areaBaselineValue)) - }, [curve, yScale, areaBaselineValue]) -} +export const useAreaGenerator = ({ + curve, + yScale, + areaBaselineValue, +}: { + curve: CurveInterpolation + yScale: any + areaBaselineValue: Exclude +}) => + useMemo( + () => + area['position']>() + .defined(d => d.x !== null && d.y !== null) + .x(d => d.x) + .y1(d => d.y) + .curve(curveFromProp(curve)) + .y0(yScale(areaBaselineValue)), + [curve, yScale, areaBaselineValue] + ) -const usePoints = ({ series, getPointColor, getPointBorderColor, formatX, formatY }) => { - return useMemo(() => { - return series.reduce((acc, serie) => { - return [ - ...acc, - ...serie.data - .filter(datum => datum.position.x !== null && datum.position.y !== null) - .map((datum, i) => { - const point = { - id: `${serie.id}.${i}`, - index: acc.length + i, - serieId: serie.id, - serieColor: serie.color, - x: datum.position.x, - y: datum.position.y, - } - point.color = getPointColor(serie) - point.borderColor = getPointBorderColor(point) - point.data = { - ...datum.data, - xFormatted: formatX(datum.data.x), - yFormatted: formatY(datum.data.y), - } - - return point - }), - ] - }, []) +const usePoints = ({ + series, + getPointColor, + getPointBorderColor, + formatX, + formatY, +}: { + series: any[] + getPointColor: any + getPointBorderColor: any + formatX: any + formatY: any +}): LinePointDatum[] => + useMemo(() => { + const points: LinePointDatum[] = [] + + series.forEach(serie => { + serie.data + // exclude undefined values + .filter(datum => datum.position.x !== null && datum.position.y !== null) + .forEach((datum, datumIndex) => { + const point = { + id: `${serie.id}.${datumIndex}`, + index: points.length, + serieId: serie.id, + serieColor: serie.color, + x: datum.position.x, + y: datum.position.y, + } + point.color = getPointColor(serie) + point.borderColor = getPointBorderColor(point) + point.data = { + ...datum.data, + xFormatted: formatX(datum.data.x), + yFormatted: formatY(datum.data.y), + } + + points.push(point) + }) + }) + + return points }, [series, getPointColor, getPointBorderColor, formatX, formatY]) -} -export const useSlices = ({ enableSlices, points, width, height }) => { - return useMemo(() => { +export const useSlices = ({ + enableSlices, + points, + width, + height, +}: { + enableSlices: LineCommonProps['enableSlices'] + points: LinePointDatum[] + width: number + height: number +}) => + useMemo(() => { if (enableSlices === false) return [] if (enableSlices === 'x') { @@ -129,30 +173,53 @@ export const useSlices = ({ enableSlices, points, width, height }) => { }) } }, [enableSlices, points]) -} -export const useLine = ({ +export const useLine = ({ data, - xScale: xScaleSpec = LineDefaultProps.xScale, + xScale: xScaleSpec = commonDefaultProps.xScale, xFormat, - yScale: yScaleSpec = LineDefaultProps.yScale, + yScale: yScaleSpec = commonDefaultProps.yScale, yFormat, width, height, colors = LineDefaultProps.colors, - curve = LineDefaultProps.curve, - areaBaselineValue = LineDefaultProps.areaBaselineValue, + curve = commonDefaultProps.curve, + areaBaselineValue = commonDefaultProps.areaBaselineValue, pointColor = LineDefaultProps.pointColor, pointBorderColor = LineDefaultProps.pointBorderColor, - enableSlices = LineDefaultProps.enableSlicesTooltip, + enableSlices = LineDefaultProps.enableSlices, +}: { + data: LineDataProps['data'] + xScale?: LineCommonProps['xScale'] + xFormat?: LineCommonProps['xFormat'] + yScale?: LineCommonProps['yScale'] + yFormat?: LineCommonProps['yFormat'] + width: number + height: number + colors: any + curve?: CurveInterpolation + areaBaselineValue?: Exclude + pointColor: any + pointBorderColor: any + enableSlices?: LineCommonProps['enableSlices'] }) => { const formatX = useValueFormatter(xFormat) const formatY = useValueFormatter(yFormat) + const getColor = useOrdinalColorScale(colors, 'id') const theme = useTheme() const getPointColor = useInheritedColor(pointColor, theme) const getPointBorderColor = useInheritedColor(pointBorderColor, theme) - const [hiddenIds, setHiddenIds] = useState([]) + + const [hiddenIds, setHiddenIds] = useState([]) + const toggleSerie = useCallback((id: string) => { + setHiddenIds(state => + state.includes(id) ? state.filter(item => item !== id) : [...state, id] + ) + }, []) + + const [currentPoint, setCurrentPoint] = useState | null>(null) + const [currentSlice, setCurrentSlice] = useState | null>(null) const { xScale, @@ -161,7 +228,7 @@ export const useLine = ({ } = useMemo( () => computeXYScalesForSeries( - data.filter(item => hiddenIds.indexOf(item.id) === -1), + data.filter(item => !hiddenIds.includes(item.id)), xScaleSpec, yScaleSpec, width, @@ -176,26 +243,25 @@ export const useLine = ({ label: line.id, color: getColor(line), })) + const series = dataWithColor .map(datum => ({ ...rawSeries.find(serie => serie.id === datum.id), color: datum.color, })) .filter(item => Boolean(item.id)) - const legendData = dataWithColor + + const _legendData = dataWithColor .map(item => ({ ...item, hidden: !series.find(serie => serie.id === item.id) })) .reverse() - return { legendData, series } + return { + series, + legendData: _legendData, + } }, [data, rawSeries, getColor]) - const toggleSerie = useCallback(id => { - setHiddenIds(state => - state.indexOf(id) > -1 ? state.filter(item => item !== id) : [...state, id] - ) - }, []) - - const points = usePoints({ + const points = usePoints({ series, getPointColor, getPointBorderColor, @@ -210,8 +276,11 @@ export const useLine = ({ height, }) - const lineGenerator = useLineGenerator({ curve }) - const areaGenerator = useAreaGenerator({ + console.log('points', points) + console.log('slices', slices) + + const lineGenerator = useLineGenerator({ curve }) + const areaGenerator = useAreaGenerator({ curve, yScale, areaBaselineValue, @@ -227,6 +296,10 @@ export const useLine = ({ xScale, yScale, slices, + currentSlice, + setCurrentSlice, points, + currentPoint, + setCurrentPoint, } } diff --git a/packages/line/src/index.ts b/packages/line/src/index.ts index 59b9f7f9b0..a08ced2a95 100644 --- a/packages/line/src/index.ts +++ b/packages/line/src/index.ts @@ -1,6 +1,7 @@ -export { default as Line } from './Line' -export { default as ResponsiveLine } from './ResponsiveLine' +export * from './Line' +export * from './ResponsiveLine' export { default as LineCanvas } from './LineCanvas' -export { default as ResponsiveLineCanvas } from './ResponsiveLineCanvas' +export * from './ResponsiveLineCanvas' export * from './props' export * from './hooks' +export * from './types' diff --git a/packages/line/src/props.tsx b/packages/line/src/props.tsx index 8a9bffb669..5a9304095c 100644 --- a/packages/line/src/props.tsx +++ b/packages/line/src/props.tsx @@ -3,8 +3,8 @@ import { lineCurvePropType, blendModePropType, motionPropTypes, defsPropTypes } import { ordinalColorsPropType } from '@nivo/colors' import { axisPropType } from '@nivo/axes' import { LegendPropShape } from '@nivo/legends' -import PointTooltip from './PointTooltip' -import SliceTooltip from './SliceTooltip' +import { PointTooltip } from './PointTooltip' +import { SliceTooltip } from './SliceTooltip' const commonPropTypes = { data: PropTypes.arrayOf( @@ -182,7 +182,7 @@ const commonDefaultProps = { isInteractive: true, tooltip: PointTooltip, - enableSlices: false, + enableSlices: false as const, debugSlices: false, sliceTooltip: SliceTooltip, debugMesh: false, diff --git a/packages/line/src/types.ts b/packages/line/src/types.ts new file mode 100644 index 0000000000..bf95b19b32 --- /dev/null +++ b/packages/line/src/types.ts @@ -0,0 +1,209 @@ +import { AriaAttributes, MouseEvent, FunctionComponent } from 'react' +import { Line, Area } from 'd3-shape' +import { + Box, + Theme, + Dimensions, + ModernMotionProps, + PropertyAccessor, + SvgDefsAndFill, + CssMixBlendMode, + ValueFormat, +} from '@nivo/core' +import { AxisProps, CanvasAxisProps } from '@nivo/axes' +import { CrosshairType } from '@nivo/tooltip' +import { ScaleSpec } from '@nivo/scales' +import { LegendProps } from '@nivo/legends' + +export type LineValue = number | string | Date | null + +export interface LineDatum { + x: LineValue + y: LineValue +} + +export interface DefaultLineDatum { + x: number | null | undefined + y: number | null | undefined +} + +export type LineSeries = { + id: string + data: Datum[] +} & ExtraProps + +export type SliceAxis = 'x' | 'y' + +export interface SliceDatum { + id: 0 + x0: number + x: number + y0: number + y: number + width: number + height: number + points: any[] +} + +export interface PointTooltipProps { + point: LinePointDatum +} +export type PointTooltipComponent = FunctionComponent< + PointTooltipProps +> + +export interface SliceTooltipProps { + slice: SliceDatum + axis: SliceAxis +} +export type SliceTooltipComponent = FunctionComponent< + SliceTooltipProps +> + +export interface LineDataProps { + data: LineSeries[] +} + +export type LineLayerId = + | 'grid' + | 'markers' + | 'axes' + | 'areas' + | 'crosshair' + | 'lines' + | 'slices' + | 'points' + | 'mesh' + | 'legends' + +export type CurveInterpolation = + | 'basis' + | 'cardinal' + | 'catmullRom' + | 'linear' + | 'monotoneX' + | 'monotoneY' + | 'natural' + | 'step' + | 'stepAfter' + | 'stepBefore' + +export type LineGenerator = Line['position']> + +export type AreaGenerator = Area['position']> + +export interface LineStyle { + lineWidth: number + opacity: number +} + +export interface LineSvgStyle extends LineStyle {} + +export interface LineCanvasStyle extends LineStyle {} + +export interface LinePointDatum { + data: Datum + position: { + x: number + y: number + } +} + +export interface PointDatum { + id: string + index: number + serieId: string + serieColor: string + x: number + y: number + data: Datum & { + xFormatted: string + yFormatted: string + } +} + +export type LineCommonProps = { + xScale: ScaleSpec + xFormat: ValueFormat> + yScale: ScaleSpec + yFormat: ValueFormat> + + margin: Box + + layers: LineLayerId[] + + enableGridX: boolean + gridXValues: Exclude[] + enableGridY: boolean + gridYValues: Exclude[] + + curve: CurveInterpolation + lineWidth: number + enableArea: boolean + areaBaselineValue: number + areaOpacity: number + areaBlendMode: CssMixBlendMode + + enablePoints: boolean + pointSize: number + // pointColor: { from: 'color' }, + pointBorderWidth: number + // pointBorderColor: { theme: 'background' }, + enablePointLabel: boolean + // pointLabel: 'yFormatted', + + theme: Theme + + // annotations: AnnotationMatcher>[] + + isInteractive: boolean + debugMesh: boolean + enableSlices: SliceAxis | false + debugSlices: boolean + sliceTooltip: SliceTooltipComponent + enableCrosshair: boolean + crosshairType: CrosshairType + onMouseEnter: (point: LinePointDatum, event: MouseEvent) => void + onMouseMove: (point: LinePointDatum, event: MouseEvent) => void + onMouseLeave: (point: LinePointDatum, event: MouseEvent) => void + onClick: (point: LinePointDatum, event: MouseEvent) => void + tooltip: PointTooltipComponent + + markers: any[] + + legends: LegendProps[] + + renderWrapper: boolean + + role: string + ariaLabel: AriaAttributes['aria-label'] + ariaLabelledBy: AriaAttributes['aria-labelledby'] + ariaDescribedBy: AriaAttributes['aria-describedby'] +} & Required + +export type LineSvgProps = Partial< + LineCommonProps +> & + LineDataProps & + Dimensions & + SvgDefsAndFill & + Partial<{ + axisTop: AxisProps | null + axisRight: AxisProps | null + axisBottom: AxisProps | null + axisLeft: AxisProps | null + useMesh: boolean + }> + +export type LineCanvasProps = Partial< + LineCommonProps +> & + LineDataProps & + Dimensions & + Partial<{ + axisTop: CanvasAxisProps> | null + axisRight: CanvasAxisProps> | null + axisBottom: CanvasAxisProps> | null + axisLeft: CanvasAxisProps> | null + pixelRatio: number + }> diff --git a/packages/line/stories/line.stories.js b/packages/line/stories/Line.stories.tsx similarity index 99% rename from packages/line/stories/line.stories.js rename to packages/line/stories/Line.stories.tsx index 3205104d38..77439d8119 100644 --- a/packages/line/stories/line.stories.js +++ b/packages/line/stories/Line.stories.tsx @@ -8,7 +8,7 @@ import { Defs, linearGradientDef } from '@nivo/core' import { area, curveMonotoneX } from 'd3-shape' import * as time from 'd3-time' import { timeFormat } from 'd3-time-format' -import { Line } from '../src' +import { Line, CurveInterpolation } from '../src' const data = generateDrinkStats(18) const commonProperties = { @@ -17,10 +17,16 @@ const commonProperties = { margin: { top: 20, right: 20, bottom: 60, left: 80 }, data, animate: true, - enableSlices: 'x', + enableSlices: 'x' as const, } -const curveOptions = ['linear', 'monotoneX', 'step', 'stepBefore', 'stepAfter'] +const curveOptions: CurveInterpolation[] = [ + 'linear', + 'monotoneX', + 'step', + 'stepBefore', + 'stepAfter', +] const CustomSymbol = ({ size, color, borderWidth, borderColor }) => ( @@ -177,7 +183,10 @@ stories.add('time scale', () => ( )) stories.add('time scale milliseconds precision', () => ( - {...commonProperties} data={[ { diff --git a/packages/line/tests/Line.test.js b/packages/line/tests/Line.test.tsx similarity index 56% rename from packages/line/tests/Line.test.js rename to packages/line/tests/Line.test.tsx index 7aa0467776..f1172339ab 100644 --- a/packages/line/tests/Line.test.js +++ b/packages/line/tests/Line.test.tsx @@ -1,9 +1,104 @@ import { mount } from 'enzyme' -import { Axis } from '@nivo/axes' -import Line from '../src/Line' -import SlicesItem from '../src/SlicesItem' -import renderer from 'react-test-renderer' +import { Line } from '../src' +import { SlicesItem } from '../src/SlicesItem' +interface TestDatum { + x: number + y: number +} + +const sampleData = [ + { + id: 'A', + data: [ + { x: 0, y: 3 }, + { x: 1, y: 7 }, + { x: 2, y: 11 }, + { x: 3, y: 9 }, + { x: 4, y: 8 }, + ], + }, + { + id: 'B', + data: [ + { x: 0, y: 1 }, + { x: 1, y: 3 }, + { x: 2, y: 5 }, + { x: 3, y: 7 }, + { x: 4, y: 11 }, + ], + }, +] + +const baseProps = { + width: 500, + height: 300, + data: sampleData, + // this is important to be able to "easily" + // extract line points' position. + curve: 'linear' as const, + animate: false, +} + +it('should render a basic line chart', () => { + const wrapper = mount( {...baseProps} />) + console.log(wrapper.debug()) +}) + +describe('slices', () => { + it('should create slice for each x value', () => { + 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 wrapper = mount( + + width={500} + height={300} + data={data} + enableSlices="x" + animate={false} + /> + ) + + const slices = wrapper.find(SlicesItem) + expect(slices).toHaveLength(5) + expect(slices.at(0).prop('slice').id).toBe(0) + expect(slices.at(1).prop('slice').id).toBe(125) + expect(slices.at(2).prop('slice').id).toBe(250) + expect(slices.at(3).prop('slice').id).toBe(375) + expect(slices.at(4).prop('slice').id).toBe(500) + }) +}) + +describe('accessibility', () => { + it('should forward root aria properties to the SVG element', () => { + const wrapper = mount( + + {...baseProps} + ariaLabel="AriaLabel" + ariaLabelledBy="AriaLabelledBy" + ariaDescribedBy="AriaDescribedBy" + /> + ) + + const svg = wrapper.find('svg') + + expect(svg.prop('aria-label')).toBe('AriaLabel') + expect(svg.prop('aria-labelledby')).toBe('AriaLabelledBy') + expect(svg.prop('aria-describedby')).toBe('AriaDescribedBy') + }) +}) + +/* it('should render a basic line chart', () => { const data = [ { @@ -53,29 +148,7 @@ it('should support multiple lines', () => { }) it('should create slice for each x value', () => { - 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 wrapper = mount( - - ) - - const slices = wrapper.find(SlicesItem) - expect(slices).toHaveLength(5) - expect(slices.at(0).prop('slice').id).toBe(0) - expect(slices.at(1).prop('slice').id).toBe(125) - expect(slices.at(2).prop('slice').id).toBe(250) - expect(slices.at(3).prop('slice').id).toBe(375) - expect(slices.at(4).prop('slice').id).toBe(500) + }) it('should have left and bottom axis by default', () => { @@ -148,3 +221,4 @@ describe('curve interpolation', () => { }) } }) +*/ diff --git a/packages/line/tests/__snapshots__/Line.test.js.snap b/packages/line/tests/__snapshots__/Line.test.js.snap deleted file mode 100644 index e8c22a85f3..0000000000 --- a/packages/line/tests/__snapshots__/Line.test.js.snap +++ /dev/null @@ -1,9565 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`curve interpolation should support basis curve interpolation 1`] = ` -
- - - - - - - - 0 - - - - - - 1 - - - - - - 2 - - - - - - 3 - - - - - - 4 - - - - - - - - - 0 - - - - - - 1 - - - - - - 2 - - - - - - 3 - - - - - - 4 - - - - - - 5 - - - - - - 6 - - - - - - 7 - - - - - - 8 - - - - - - 9 - - - - - - 10 - - - - - - 11 - - - - - - - - - - - - - - - - - - - - - - - - -
-`; - -exports[`curve interpolation should support cardinal curve interpolation 1`] = ` -
- - - - - - - - 0 - - - - - - 1 - - - - - - 2 - - - - - - 3 - - - - - - 4 - - - - - - - - - 0 - - - - - - 1 - - - - - - 2 - - - - - - 3 - - - - - - 4 - - - - - - 5 - - - - - - 6 - - - - - - 7 - - - - - - 8 - - - - - - 9 - - - - - - 10 - - - - - - 11 - - - - - - - - - - - - - - - - - - - - - - - - -
-`; - -exports[`curve interpolation should support catmullRom curve interpolation 1`] = ` -
- - - - - - - - 0 - - - - - - 1 - - - - - - 2 - - - - - - 3 - - - - - - 4 - - - - - - - - - 0 - - - - - - 1 - - - - - - 2 - - - - - - 3 - - - - - - 4 - - - - - - 5 - - - - - - 6 - - - - - - 7 - - - - - - 8 - - - - - - 9 - - - - - - 10 - - - - - - 11 - - - - - - - - - - - - - - - - - - - - - - - - -
-`; - -exports[`curve interpolation should support linear curve interpolation 1`] = ` -
- - - - - - - - 0 - - - - - - 1 - - - - - - 2 - - - - - - 3 - - - - - - 4 - - - - - - - - - 0 - - - - - - 1 - - - - - - 2 - - - - - - 3 - - - - - - 4 - - - - - - 5 - - - - - - 6 - - - - - - 7 - - - - - - 8 - - - - - - 9 - - - - - - 10 - - - - - - 11 - - - - - - - - - - - - - - - - - - - - - - - - -
-`; - -exports[`curve interpolation should support monotoneX curve interpolation 1`] = ` -
- - - - - - - - 0 - - - - - - 1 - - - - - - 2 - - - - - - 3 - - - - - - 4 - - - - - - - - - 0 - - - - - - 1 - - - - - - 2 - - - - - - 3 - - - - - - 4 - - - - - - 5 - - - - - - 6 - - - - - - 7 - - - - - - 8 - - - - - - 9 - - - - - - 10 - - - - - - 11 - - - - - - - - - - - - - - - - - - - - - - - - -
-`; - -exports[`curve interpolation should support monotoneY curve interpolation 1`] = ` -
- - - - - - - - 0 - - - - - - 1 - - - - - - 2 - - - - - - 3 - - - - - - 4 - - - - - - - - - 0 - - - - - - 1 - - - - - - 2 - - - - - - 3 - - - - - - 4 - - - - - - 5 - - - - - - 6 - - - - - - 7 - - - - - - 8 - - - - - - 9 - - - - - - 10 - - - - - - 11 - - - - - - - - - - - - - - - - - - - - - - - - -
-`; - -exports[`curve interpolation should support natural curve interpolation 1`] = ` -
- - - - - - - - 0 - - - - - - 1 - - - - - - 2 - - - - - - 3 - - - - - - 4 - - - - - - - - - 0 - - - - - - 1 - - - - - - 2 - - - - - - 3 - - - - - - 4 - - - - - - 5 - - - - - - 6 - - - - - - 7 - - - - - - 8 - - - - - - 9 - - - - - - 10 - - - - - - 11 - - - - - - - - - - - - - - - - - - - - - - - - -
-`; - -exports[`curve interpolation should support step curve interpolation 1`] = ` -
- - - - - - - - 0 - - - - - - 1 - - - - - - 2 - - - - - - 3 - - - - - - 4 - - - - - - - - - 0 - - - - - - 1 - - - - - - 2 - - - - - - 3 - - - - - - 4 - - - - - - 5 - - - - - - 6 - - - - - - 7 - - - - - - 8 - - - - - - 9 - - - - - - 10 - - - - - - 11 - - - - - - - - - - - - - - - - - - - - - - - - -
-`; - -exports[`curve interpolation should support stepAfter curve interpolation 1`] = ` -
- - - - - - - - 0 - - - - - - 1 - - - - - - 2 - - - - - - 3 - - - - - - 4 - - - - - - - - - 0 - - - - - - 1 - - - - - - 2 - - - - - - 3 - - - - - - 4 - - - - - - 5 - - - - - - 6 - - - - - - 7 - - - - - - 8 - - - - - - 9 - - - - - - 10 - - - - - - 11 - - - - - - - - - - - - - - - - - - - - - - - - -
-`; - -exports[`curve interpolation should support stepBefore curve interpolation 1`] = ` -
- - - - - - - - 0 - - - - - - 1 - - - - - - 2 - - - - - - 3 - - - - - - 4 - - - - - - - - - 0 - - - - - - 1 - - - - - - 2 - - - - - - 3 - - - - - - 4 - - - - - - 5 - - - - - - 6 - - - - - - 7 - - - - - - 8 - - - - - - 9 - - - - - - 10 - - - - - - 11 - - - - - - - - - - - - - - - - - - - - - - - - -
-`; - -exports[`should render a basic line chart 1`] = ` -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 - - - - - - 1 - - - - - - 2 - - - - - - 3 - - - - - - 4 - - - - - - - - - 0 - - - - - - 1 - - - - - - 2 - - - - - - 3 - - - - - - 4 - - - - - - 5 - - - - - - 6 - - - - - - 7 - - - - - - 8 - - - - - - 9 - - - - - - 10 - - - - - - 11 - - - - - - - - - - - - - - - - - - - - - - - - -
-`; - -exports[`should support multiple lines 1`] = ` -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 - - - - - - 1 - - - - - - 2 - - - - - - 3 - - - - - - 4 - - - - - - - - - 0 - - - - - - 1 - - - - - - 2 - - - - - - 3 - - - - - - 4 - - - - - - 5 - - - - - - 6 - - - - - - 7 - - - - - - 8 - - - - - - 9 - - - - - - 10 - - - - - - 11 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-`;