From ad0af5cb3b286af606c6f41645f190aa1e28c720 Mon Sep 17 00:00:00 2001 From: Chris Williams Date: Fri, 27 Dec 2019 10:16:35 -0800 Subject: [PATCH 01/13] typescript(vx-axis): add types to package.json, add type deps --- packages/vx-axis/package.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/vx-axis/package.json b/packages/vx-axis/package.json index b489b3bf42..0de96c810e 100644 --- a/packages/vx-axis/package.json +++ b/packages/vx-axis/package.json @@ -5,6 +5,7 @@ "sideEffects": false, "main": "lib/index.js", "module": "esm/index.js", + "types": "lib/index.d.ts", "scripts": { "docs": "cd ./docs && ../../../node_modules/.bin/react-docgen ../src/axis/ | ../../../scripts/buildDocs.sh" }, @@ -30,6 +31,9 @@ }, "homepage": "https://github.com/hshoff/vx#readme", "dependencies": { + "@types/classnames": "^2.2.9", + "@types/d3-scale": "^2.1.1", + "@types/react": "*", "@vx/group": "0.0.192", "@vx/point": "0.0.192", "@vx/shape": "0.0.192", From ca3a9f902d0d71a3a25e8a6b938134b93ac5ac81 Mon Sep 17 00:00:00 2001 From: Chris Williams Date: Fri, 27 Dec 2019 10:17:11 -0800 Subject: [PATCH 02/13] typescript(vx-axis): rename .js(x) => .ts(x) --- packages/vx-axis/src/axis/{Axis.jsx => Axis.tsx} | 0 packages/vx-axis/src/axis/{AxisBottom.jsx => AxisBottom.tsx} | 0 packages/vx-axis/src/axis/{AxisLeft.jsx => AxisLeft.tsx} | 0 packages/vx-axis/src/axis/{AxisRight.jsx => AxisRight.tsx} | 0 packages/vx-axis/src/axis/{AxisTop.jsx => AxisTop.tsx} | 0 packages/vx-axis/src/constants/{orientation.js => orientation.ts} | 0 packages/vx-axis/src/{index.js => index.ts} | 0 packages/vx-axis/src/utils/{center.js => center.ts} | 0 packages/vx-axis/src/utils/{identity.js => identity.ts} | 0 .../vx-axis/src/utils/{labelTransform.js => labelTransform.ts} | 0 packages/vx-axis/test/{Axis.test.jsx => Axis.test.tsx} | 0 .../vx-axis/test/{AxisBottom.test.jsx => AxisBottom.test.tsx} | 0 packages/vx-axis/test/{AxisLeft.test.jsx => AxisLeft.test.tsx} | 0 packages/vx-axis/test/{AxisRight.test.jsx => AxisRight.test.tsx} | 0 packages/vx-axis/test/{AxisTop.test.jsx => AxisTop.test.tsx} | 0 .../vx-axis/test/{Orientation.test.js => Orientation.test.ts} | 0 16 files changed, 0 insertions(+), 0 deletions(-) rename packages/vx-axis/src/axis/{Axis.jsx => Axis.tsx} (100%) rename packages/vx-axis/src/axis/{AxisBottom.jsx => AxisBottom.tsx} (100%) rename packages/vx-axis/src/axis/{AxisLeft.jsx => AxisLeft.tsx} (100%) rename packages/vx-axis/src/axis/{AxisRight.jsx => AxisRight.tsx} (100%) rename packages/vx-axis/src/axis/{AxisTop.jsx => AxisTop.tsx} (100%) rename packages/vx-axis/src/constants/{orientation.js => orientation.ts} (100%) rename packages/vx-axis/src/{index.js => index.ts} (100%) rename packages/vx-axis/src/utils/{center.js => center.ts} (100%) rename packages/vx-axis/src/utils/{identity.js => identity.ts} (100%) rename packages/vx-axis/src/utils/{labelTransform.js => labelTransform.ts} (100%) rename packages/vx-axis/test/{Axis.test.jsx => Axis.test.tsx} (100%) rename packages/vx-axis/test/{AxisBottom.test.jsx => AxisBottom.test.tsx} (100%) rename packages/vx-axis/test/{AxisLeft.test.jsx => AxisLeft.test.tsx} (100%) rename packages/vx-axis/test/{AxisRight.test.jsx => AxisRight.test.tsx} (100%) rename packages/vx-axis/test/{AxisTop.test.jsx => AxisTop.test.tsx} (100%) rename packages/vx-axis/test/{Orientation.test.js => Orientation.test.ts} (100%) diff --git a/packages/vx-axis/src/axis/Axis.jsx b/packages/vx-axis/src/axis/Axis.tsx similarity index 100% rename from packages/vx-axis/src/axis/Axis.jsx rename to packages/vx-axis/src/axis/Axis.tsx diff --git a/packages/vx-axis/src/axis/AxisBottom.jsx b/packages/vx-axis/src/axis/AxisBottom.tsx similarity index 100% rename from packages/vx-axis/src/axis/AxisBottom.jsx rename to packages/vx-axis/src/axis/AxisBottom.tsx diff --git a/packages/vx-axis/src/axis/AxisLeft.jsx b/packages/vx-axis/src/axis/AxisLeft.tsx similarity index 100% rename from packages/vx-axis/src/axis/AxisLeft.jsx rename to packages/vx-axis/src/axis/AxisLeft.tsx diff --git a/packages/vx-axis/src/axis/AxisRight.jsx b/packages/vx-axis/src/axis/AxisRight.tsx similarity index 100% rename from packages/vx-axis/src/axis/AxisRight.jsx rename to packages/vx-axis/src/axis/AxisRight.tsx diff --git a/packages/vx-axis/src/axis/AxisTop.jsx b/packages/vx-axis/src/axis/AxisTop.tsx similarity index 100% rename from packages/vx-axis/src/axis/AxisTop.jsx rename to packages/vx-axis/src/axis/AxisTop.tsx diff --git a/packages/vx-axis/src/constants/orientation.js b/packages/vx-axis/src/constants/orientation.ts similarity index 100% rename from packages/vx-axis/src/constants/orientation.js rename to packages/vx-axis/src/constants/orientation.ts diff --git a/packages/vx-axis/src/index.js b/packages/vx-axis/src/index.ts similarity index 100% rename from packages/vx-axis/src/index.js rename to packages/vx-axis/src/index.ts diff --git a/packages/vx-axis/src/utils/center.js b/packages/vx-axis/src/utils/center.ts similarity index 100% rename from packages/vx-axis/src/utils/center.js rename to packages/vx-axis/src/utils/center.ts diff --git a/packages/vx-axis/src/utils/identity.js b/packages/vx-axis/src/utils/identity.ts similarity index 100% rename from packages/vx-axis/src/utils/identity.js rename to packages/vx-axis/src/utils/identity.ts diff --git a/packages/vx-axis/src/utils/labelTransform.js b/packages/vx-axis/src/utils/labelTransform.ts similarity index 100% rename from packages/vx-axis/src/utils/labelTransform.js rename to packages/vx-axis/src/utils/labelTransform.ts diff --git a/packages/vx-axis/test/Axis.test.jsx b/packages/vx-axis/test/Axis.test.tsx similarity index 100% rename from packages/vx-axis/test/Axis.test.jsx rename to packages/vx-axis/test/Axis.test.tsx diff --git a/packages/vx-axis/test/AxisBottom.test.jsx b/packages/vx-axis/test/AxisBottom.test.tsx similarity index 100% rename from packages/vx-axis/test/AxisBottom.test.jsx rename to packages/vx-axis/test/AxisBottom.test.tsx diff --git a/packages/vx-axis/test/AxisLeft.test.jsx b/packages/vx-axis/test/AxisLeft.test.tsx similarity index 100% rename from packages/vx-axis/test/AxisLeft.test.jsx rename to packages/vx-axis/test/AxisLeft.test.tsx diff --git a/packages/vx-axis/test/AxisRight.test.jsx b/packages/vx-axis/test/AxisRight.test.tsx similarity index 100% rename from packages/vx-axis/test/AxisRight.test.jsx rename to packages/vx-axis/test/AxisRight.test.tsx diff --git a/packages/vx-axis/test/AxisTop.test.jsx b/packages/vx-axis/test/AxisTop.test.tsx similarity index 100% rename from packages/vx-axis/test/AxisTop.test.jsx rename to packages/vx-axis/test/AxisTop.test.tsx diff --git a/packages/vx-axis/test/Orientation.test.js b/packages/vx-axis/test/Orientation.test.ts similarity index 100% rename from packages/vx-axis/test/Orientation.test.js rename to packages/vx-axis/test/Orientation.test.ts From b472085fa8ce167b38d96ac3592f3d4f5ec10fbf Mon Sep 17 00:00:00 2001 From: Chris Williams Date: Fri, 27 Dec 2019 14:26:11 -0800 Subject: [PATCH 03/13] typescript(vx-text): re-write package in TypeScript --- packages/vx-axis/src/axis/Axis.tsx | 70 +++----- packages/vx-axis/src/axis/AxisBottom.tsx | 112 +----------- packages/vx-axis/src/axis/AxisLeft.tsx | 37 +--- packages/vx-axis/src/axis/AxisRight.tsx | 37 +--- packages/vx-axis/src/axis/AxisTop.tsx | 37 +--- packages/vx-axis/src/constants/orientation.ts | 6 +- packages/vx-axis/src/types.ts | 159 ++++++++++++++++++ packages/vx-axis/src/utils/center.ts | 19 ++- packages/vx-axis/src/utils/identity.ts | 2 +- packages/vx-axis/src/utils/labelTransform.ts | 27 ++- packages/vx-axis/src/utils/toString.ts | 3 + packages/vx-axis/test/Axis.test.tsx | 2 +- packages/vx-axis/test/AxisBottom.test.tsx | 2 +- packages/vx-axis/test/AxisLeft.test.tsx | 2 +- packages/vx-axis/test/AxisRight.test.tsx | 2 +- packages/vx-axis/test/AxisTop.test.tsx | 2 +- packages/vx-text/src/Text.tsx | 2 + 17 files changed, 248 insertions(+), 273 deletions(-) create mode 100644 packages/vx-axis/src/types.ts create mode 100644 packages/vx-axis/src/utils/toString.ts diff --git a/packages/vx-axis/src/axis/Axis.tsx b/packages/vx-axis/src/axis/Axis.tsx index 145f525ebb..ed9c54f2bf 100644 --- a/packages/vx-axis/src/axis/Axis.tsx +++ b/packages/vx-axis/src/axis/Axis.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import PropTypes from 'prop-types'; import cx from 'classnames'; import { Line } from '@vx/shape'; import { Point } from '@vx/point'; @@ -9,38 +8,14 @@ import center from '../utils/center'; import identity from '../utils/identity'; import getLabelTransform from '../utils/labelTransform'; import ORIENT from '../constants/orientation'; +import toString from '../utils/toString'; +import { SharedAxisProps, AxisOrientation, TickFormatter } from '../types'; -const propTypes = { - axisClassName: PropTypes.string, - axisLineClassName: PropTypes.string, - hideAxisLine: PropTypes.bool, - hideTicks: PropTypes.bool, - hideZero: PropTypes.bool, - label: PropTypes.string, - labelClassName: PropTypes.string, - labelOffset: PropTypes.number, - labelProps: PropTypes.object, - left: PropTypes.number, - numTicks: PropTypes.number, - orientation: PropTypes.oneOf([ORIENT.top, ORIENT.right, ORIENT.bottom, ORIENT.left]), - rangePadding: PropTypes.number, - scale: PropTypes.func.isRequired, - stroke: PropTypes.string, - strokeWidth: PropTypes.number, - strokeDasharray: PropTypes.string, - tickClassName: PropTypes.string, - tickFormat: PropTypes.func, - tickLabelProps: PropTypes.func, - tickLength: PropTypes.number, - tickStroke: PropTypes.string, - tickTransform: PropTypes.string, - tickValues: PropTypes.array, - tickComponent: PropTypes.func, - top: PropTypes.number, - children: PropTypes.func, +export type AxisProps = SharedAxisProps & { + orientation: AxisOrientation; }; -export default function Axis({ +export default function Axis({ children, axisClassName, axisLineClassName, @@ -78,10 +53,10 @@ export default function Axis({ tickValues, tickComponent, top = 0, -}) { +}: AxisProps) { let values = scale.ticks ? scale.ticks(numTicks) : scale.domain(); if (tickValues) values = tickValues; - let format = scale.tickFormat ? scale.tickFormat() : identity; + let format: TickFormatter = scale.tickFormat ? scale.tickFormat() : toString; if (tickFormat) format = tickFormat; const range = scale.range(); @@ -145,8 +120,12 @@ export default function Axis({ return ( {values.map((val, index) => { - if (hideZero && val === 0) return null; - + if ( + hideZero && + ((typeof val === 'number' && val === 0) || (typeof val === 'string' && val === '0')) + ) { + return null; + } const tickFromPoint = new Point({ x: horizontal ? position(val) : 0, y: horizontal ? 0 : position(val), @@ -157,8 +136,13 @@ export default function Axis({ }); const tickLabelPropsObj = tickLabelProps(val, index); - tickLabelFontSize = Math.max(tickLabelFontSize, tickLabelPropsObj.fontSize || 0); + tickLabelFontSize = Math.max( + tickLabelFontSize, + (typeof tickLabelPropsObj.fontSize === 'number' && tickLabelPropsObj.fontSize) || 0, + ); + const tickYCoord = tickToPoint.y + (horizontal && !isTop ? tickLabelFontSize : 0); + const formattedValue = format(val, index); return ( } {tickComponent ? ( tickComponent({ - x: tickToPoint.x, - y: tickToPoint.y + (horizontal && !isTop ? tickLabelFontSize : 0), - formattedValue: format(val, index), ...tickLabelPropsObj, + x: tickToPoint.x, + y: tickYCoord, + formattedValue, }) ) : ( - - {format(val, index)} + + {formattedValue} )} @@ -216,5 +196,3 @@ export default function Axis({ ); } - -Axis.propTypes = propTypes; diff --git a/packages/vx-axis/src/axis/AxisBottom.tsx b/packages/vx-axis/src/axis/AxisBottom.tsx index 3d0fc0d4f2..930632f97c 100644 --- a/packages/vx-axis/src/axis/AxisBottom.tsx +++ b/packages/vx-axis/src/axis/AxisBottom.tsx @@ -1,114 +1,12 @@ import React from 'react'; -import PropTypes from 'prop-types'; import cx from 'classnames'; import Axis from './Axis'; import ORIENT from '../constants/orientation'; +import { SharedAxisProps } from '../types'; -const propTypes = { - /** - * The class name applied to the outermost axis group element. - */ - axisClassName: PropTypes.string, - /** - * The class name applied to the axis line element. - */ - axisLineClassName: PropTypes.string, - /** - * If true, will hide the axis line. - */ - hideAxisLine: PropTypes.bool, - /** - * If true, will hide the ticks (but not the tick labels). - */ - hideTicks: PropTypes.bool, - /** - * If true, will hide the '0' value tick and tick label. - */ - hideZero: PropTypes.bool, - /** - * The text for the axis label. - */ - label: PropTypes.string, - /** - * The class name applied to the axis label text element. - */ - labelClassName: PropTypes.string, - /** - * Pixel offset of the axis label (does not include tick label font size, which is accounted for automatically) - */ - labelOffset: PropTypes.number, - /** - * Props applied to the axis label component. - */ - labelProps: PropTypes.object, - /** - * A left pixel offset applied to the entire axis. - */ - left: PropTypes.number, - /** - * The number of ticks wanted for the axis (note this is approximate) - */ - numTicks: PropTypes.number, - /** - * Pixel padding to apply to both sides of the axis. - */ - rangePadding: PropTypes.number, - /** - * A [d3](https://github.com/d3/d3-scale) or [vx](https://github.com/hshoff/vx/tree/master/packages/vx-scale) scale function. - */ - scale: PropTypes.func.isRequired, - /** - * The color for the stroke of the lines. - */ - stroke: PropTypes.string, - /** - * The pixel value for the width of the lines. - */ - strokeWidth: PropTypes.number, - /** - * The pattern of dashes in the stroke. - */ - strokeDasharray: PropTypes.string, - /** - * The class name applied to each tick group. - */ - tickClassName: PropTypes.string, - /** - * A [d3 formatter](https://github.com/d3/d3-scale/blob/master/README.md#continuous_tickFormat) for the tick text. - */ - tickFormat: PropTypes.func, - /** - * A function that returns props for a given tick label. - */ - tickLabelProps: PropTypes.func, - /** - * The length of the tick lines. - */ - tickLength: PropTypes.number, - /** - * The color for the tick's stroke value. - */ - tickStroke: PropTypes.string, - /** - * A custom SVG transform value to be applied to each tick group. - */ - tickTransform: PropTypes.string, - /** - * An array of values that determine the number and values of the ticks. Falls back to `scale.ticks()` or `.domain()`. - */ - tickValues: PropTypes.array, - tickComponent: PropTypes.func, - /** - * A top pixel offset applied to the entire axis. - */ - top: PropTypes.number, - /** - * For more control over rendering or to add event handlers to datum, pass a function as children. - */ - children: PropTypes.func, -}; +export type AxisBottomProps = SharedAxisProps; -export default function AxisBottom({ +export default function AxisBottom({ children, axisClassName, axisLineClassName, @@ -141,7 +39,7 @@ export default function AxisBottom({ tickValues, tickComponent, top, -}) { +}: AxisBottomProps) { return ( ); } - -AxisBottom.propTypes = propTypes; diff --git a/packages/vx-axis/src/axis/AxisLeft.tsx b/packages/vx-axis/src/axis/AxisLeft.tsx index 9a1d7f9625..bd65dedeb2 100644 --- a/packages/vx-axis/src/axis/AxisLeft.tsx +++ b/packages/vx-axis/src/axis/AxisLeft.tsx @@ -1,39 +1,12 @@ import React from 'react'; -import PropTypes from 'prop-types'; import cx from 'classnames'; import Axis from './Axis'; import ORIENT from '../constants/orientation'; +import { SharedAxisProps } from '../types'; -const propTypes = { - axisClassName: PropTypes.string, - axisLineClassName: PropTypes.string, - hideAxisLine: PropTypes.bool, - hideTicks: PropTypes.bool, - hideZero: PropTypes.bool, - label: PropTypes.string, - labelClassName: PropTypes.string, - labelOffset: PropTypes.number, - labelProps: PropTypes.object, - left: PropTypes.number, - numTicks: PropTypes.number, - rangePadding: PropTypes.number, - scale: PropTypes.func.isRequired, - stroke: PropTypes.string, - strokeWidth: PropTypes.number, - strokeDasharray: PropTypes.string, - tickClassName: PropTypes.string, - tickFormat: PropTypes.func, - tickLabelProps: PropTypes.func, - tickLength: PropTypes.number, - tickStroke: PropTypes.string, - tickTransform: PropTypes.string, - tickValues: PropTypes.array, - tickComponent: PropTypes.func, - top: PropTypes.number, - children: PropTypes.func, -}; +export type AxisLeftProps = SharedAxisProps; -export default function AxisLeft({ +export default function AxisLeft({ children, axisClassName, axisLineClassName, @@ -67,7 +40,7 @@ export default function AxisLeft({ tickValues, tickComponent, top, -}) { +}: AxisLeftProps) { return ( ); } - -AxisLeft.propTypes = propTypes; diff --git a/packages/vx-axis/src/axis/AxisRight.tsx b/packages/vx-axis/src/axis/AxisRight.tsx index 11445cf728..a9c125731d 100644 --- a/packages/vx-axis/src/axis/AxisRight.tsx +++ b/packages/vx-axis/src/axis/AxisRight.tsx @@ -1,39 +1,12 @@ import React from 'react'; -import PropTypes from 'prop-types'; import cx from 'classnames'; import Axis from './Axis'; import ORIENT from '../constants/orientation'; +import { SharedAxisProps } from '../types'; -const propTypes = { - axisClassName: PropTypes.string, - axisLineClassName: PropTypes.string, - hideAxisLine: PropTypes.bool, - hideTicks: PropTypes.bool, - hideZero: PropTypes.bool, - label: PropTypes.string, - labelClassName: PropTypes.string, - labelOffset: PropTypes.number, - labelProps: PropTypes.object, - left: PropTypes.number, - numTicks: PropTypes.number, - rangePadding: PropTypes.number, - scale: PropTypes.func.isRequired, - stroke: PropTypes.string, - strokeWidth: PropTypes.number, - strokeDasharray: PropTypes.string, - tickClassName: PropTypes.string, - tickFormat: PropTypes.func, - tickLabelProps: PropTypes.func, - tickLength: PropTypes.number, - tickStroke: PropTypes.string, - tickTransform: PropTypes.string, - tickValues: PropTypes.array, - tickComponent: PropTypes.func, - top: PropTypes.number, - children: PropTypes.func, -}; +export type AxisRightProps = SharedAxisProps; -export default function AxisRight({ +export default function AxisRight({ children, axisClassName, axisLineClassName, @@ -67,7 +40,7 @@ export default function AxisRight({ tickValues, tickComponent, top, -}) { +}: AxisRightProps) { return ( ); } - -AxisRight.propTypes = propTypes; diff --git a/packages/vx-axis/src/axis/AxisTop.tsx b/packages/vx-axis/src/axis/AxisTop.tsx index d0cdadf87a..7e65dca388 100644 --- a/packages/vx-axis/src/axis/AxisTop.tsx +++ b/packages/vx-axis/src/axis/AxisTop.tsx @@ -1,39 +1,12 @@ import React from 'react'; -import PropTypes from 'prop-types'; import cx from 'classnames'; import Axis from './Axis'; import ORIENT from '../constants/orientation'; +import { SharedAxisProps } from '../types'; -const propTypes = { - axisClassName: PropTypes.string, - axisLineClassName: PropTypes.string, - hideAxisLine: PropTypes.bool, - hideTicks: PropTypes.bool, - hideZero: PropTypes.bool, - label: PropTypes.string, - labelClassName: PropTypes.string, - labelOffset: PropTypes.number, - labelProps: PropTypes.object, - left: PropTypes.number, - numTicks: PropTypes.number, - rangePadding: PropTypes.number, - scale: PropTypes.func.isRequired, - stroke: PropTypes.string, - strokeWidth: PropTypes.number, - strokeDasharray: PropTypes.string, - tickClassName: PropTypes.string, - tickFormat: PropTypes.func, - tickLabelProps: PropTypes.func, - tickLength: PropTypes.number, - tickStroke: PropTypes.string, - tickTransform: PropTypes.string, - tickValues: PropTypes.array, - tickComponent: PropTypes.func, - top: PropTypes.number, - children: PropTypes.func, -}; +export type AxisTopProps = SharedAxisProps; -export default function AxisTop({ +export default function AxisTop({ children, axisClassName, axisLineClassName, @@ -66,7 +39,7 @@ export default function AxisTop({ tickValues, tickComponent, top, -}) { +}: AxisTopProps) { return ( ); } - -AxisTop.propTypes = propTypes; diff --git a/packages/vx-axis/src/constants/orientation.ts b/packages/vx-axis/src/constants/orientation.ts index 7f35efa2e7..57189db185 100644 --- a/packages/vx-axis/src/constants/orientation.ts +++ b/packages/vx-axis/src/constants/orientation.ts @@ -1,6 +1,10 @@ -export default { +import { AxisOrientation } from '../types'; + +const orientation: Record = { top: 'top', left: 'left', right: 'right', bottom: 'bottom', }; + +export default orientation; diff --git a/packages/vx-axis/src/types.ts b/packages/vx-axis/src/types.ts new file mode 100644 index 0000000000..738c45d287 --- /dev/null +++ b/packages/vx-axis/src/types.ts @@ -0,0 +1,159 @@ +import { TextProps } from '@vx/text/lib/Text'; + +export type AxisOrientation = 'top' | 'right' | 'bottom' | 'left'; + +type Output = number; + +export type FormattedValue = string | undefined; + +export type TickFormatter = (value: Input, tickIndex: number) => FormattedValue; + +export type TickLabelProps = (val: Input, index: number) => Partial; + +export type TickRendererProps = { + x: number; + y: number; + formattedValue: FormattedValue; +} & Omit, 'x' | 'y'>; + +export type SharedAxisProps = { + /** The class name applied to the outermost axis group element. */ + axisClassName?: string; + /** The class name applied to the axis line element. */ + axisLineClassName?: string; + /** If true, will hide the axis line. */ + hideAxisLine?: boolean; + /** If true, will hide the ticks (but not the tick labels). */ + hideTicks: boolean; + /** If true, will hide the '0' value tick and tick label. */ + hideZero: boolean; + /** The text for the axis label. */ + label?: string; + /** The class name applied to the axis label text element. */ + labelClassName?: string; + /** Pixel offset of the axis label (does not include tick label font size, which is accounted for automatically) */ + labelOffset?: number; + /** Props applied to the axis label component. */ + labelProps?: {}; + /** A left pixel offset applied to the entire axis. */ + left?: number; + /** The number of ticks wanted for the axis (note this is approximate) */ + numTicks?: number; + /** Pixel padding to apply to both sides of the axis. */ + rangePadding?: number; + /** A [d3](https://github.com/d3/d3-scale) or [vx](https://github.com/hshoff/vx/tree/master/packages/vx-scale) scale function. */ + scale: GenericScale; + /** The color for the stroke of the lines. */ + stroke?: string; + /** The pixel value for the width of the lines. */ + strokeWidth?: number; + /** The pattern of dashes in the stroke. */ + strokeDasharray?: string; + /** The class name applied to each tick group. */ + tickClassName?: string; + /** A [d3 formatter](https://github.com/d3/d3-scale/blob/master/README.md#continuous_tickFormat) for the tick text. */ + tickFormat: TickFormatter; + /** A function that returns props for a given tick label. */ + tickLabelProps: TickLabelProps; + /** The length of the tick lines. */ + tickLength?: number; + /** The color for the tick's stroke value. */ + tickStroke?: string; + /** A custom SVG transform value to be applied to each tick group. */ + tickTransform?: string; + /** An array of values that determine the number and values of the ticks. Falls back to `scale.ticks()` or `.domain()`. */ + tickValues: Input[]; + /** */ + tickComponent: (tickRendererProps: TickRendererProps) => React.ReactNode; + /** A top pixel offset applied to the entire axis. */ + top?: number; + /** For more control over rendering or to add event handlers to datum, pass a function as children. */ + children: (renderProps: ChildRenderProps) => React.ReactNode; +}; + +export interface GenericScale { + (value: Input): Output; + domain(input: Input[]): this; + domain(): Input[] | [Input, Input]; + range(): Output[] | [Output, Output]; + range(output: Output[]): this; + ticks?: (count: number) => Input[] | [Input, Input]; + bandwidth?: () => number; + round?: () => boolean; + tickFormat?: () => (input: Input) => FormattedValue; + copy(): this; +} + +export interface Point { + x: number; + y: number; +} + +export type ChildRenderProps = { + axisFromPoint: Point; + axisToPoint: Point; + horizontal: boolean; + /** Axis coordinate sign, -1 for left or top orientation. */ + tickSign: 1 | -1; + numTicks: number; + label?: string; + rangePadding: number; + tickLength: number; + tickFormat: TickFormatter; + tickPosition: (value: Input) => Output; + ticks: { + value: Input; + index: number; + from: Point; + to: Point; + formattedValue: Input | string | undefined | null; + }[]; + // ticks: values.map((value, index) => { + // const from = new Point({ + // x: horizontal ? position(value) : 0, + // y: horizontal ? 0 : position(value), + // }); + // const to = new Point({ + // x: horizontal ? position(value) : tickSign * tickLength, + // y: horizontal ? tickLength * tickSign : position(value), + // }); + // return { + // value, + // index, + // from, + // to, + // formattedValue: format(value, index), + // }; + // }), +}; + +// eslint doesn't know about @types/d3-scale +// eslint-disable-next-line import/no-extraneous-dependencies +// import { +// ScaleBand, +// ScaleLinear, +// ScaleLogarithmic, +// ScaleOrdinal, +// ScaleQuantile, +// ScaleQuantize, +// ScaleThreshold, +// ScalePower, +// ScaleTime, +// } from 'd3-scale'; + +// numberic domain +// export type ScaleType< +// Input = unknown, +// Output = unknown, +// > = +// | ScaleBand +// | ScaleLinear +// | ScaleLogarithmic +// | ScaleOrdinal +// | ScaleQuantile +// | ScaleQuantize +// | ScaleThreshold; + +// export type ScaleType = S extends ScaleBand +// ? ScaleBandScaleBand +// : ScaleLinear; diff --git a/packages/vx-axis/src/utils/center.ts b/packages/vx-axis/src/utils/center.ts index dd033fff1a..c0f0804821 100644 --- a/packages/vx-axis/src/utils/center.ts +++ b/packages/vx-axis/src/utils/center.ts @@ -1,7 +1,16 @@ -export default function center(scale) { - let offset = scale.bandwidth() / 2; - if (scale.round()) offset = Math.round(offset); - return d => { - return scale(d) + offset; +import { GenericScale } from '../types'; + +/** + * Returns a function that applies a centering transform to a scaled value, + * if `Output` is of type `number` and `scale.bandwidth()` is defined + */ +export default function center(scale: GenericScale) { + let offset = scale.bandwidth ? scale.bandwidth() / 2 : 0; + + if (scale.round && scale.round()) offset = Math.round(offset); + + return (d: Input) => { + const scaledValue = scale(d); + return typeof scaledValue === 'number' ? scaledValue + offset : scaledValue; }; } diff --git a/packages/vx-axis/src/utils/identity.ts b/packages/vx-axis/src/utils/identity.ts index 0c86fdf011..5538f47174 100644 --- a/packages/vx-axis/src/utils/identity.ts +++ b/packages/vx-axis/src/utils/identity.ts @@ -1,3 +1,3 @@ -export default function identity(x) { +export default function identity(x: T) { return x; } diff --git a/packages/vx-axis/src/utils/labelTransform.ts b/packages/vx-axis/src/utils/labelTransform.ts index 3a53c2a1d0..8147b11b0c 100644 --- a/packages/vx-axis/src/utils/labelTransform.ts +++ b/packages/vx-axis/src/utils/labelTransform.ts @@ -1,4 +1,15 @@ +import { TextProps } from '@vx/text/lib/Text'; import ORIENT from '../constants/orientation'; +import { AxisOrientation } from '../types'; + +export interface TransformArgs { + labelOffset: number; + labelProps: Partial; + orientation: AxisOrientation; + range: number[]; + tickLabelFontSize: number; + tickLength: number; +} export default function labelTransform({ labelOffset, @@ -7,21 +18,21 @@ export default function labelTransform({ range, tickLabelFontSize, tickLength, -}) { +}: TransformArgs) { const sign = orientation === ORIENT.left || orientation === ORIENT.top ? -1 : 1; let x; let y; - let transform = null; + let transform; if (orientation === ORIENT.top || orientation === ORIENT.bottom) { + const yBottomOffset = + orientation === ORIENT.bottom && typeof labelProps.fontSize === 'number' + ? labelProps.fontSize + : 0; + x = (range[0] + range[range.length - 1]) / 2; - y = - sign * - (tickLength + - labelOffset + - tickLabelFontSize + - (orientation === ORIENT.bottom ? labelProps.fontSize : 0)); + y = sign * (tickLength + labelOffset + tickLabelFontSize + yBottomOffset); } else { x = sign * ((range[0] + range[range.length - 1]) / 2); y = -(tickLength + labelOffset); diff --git a/packages/vx-axis/src/utils/toString.ts b/packages/vx-axis/src/utils/toString.ts new file mode 100644 index 0000000000..aab868cc95 --- /dev/null +++ b/packages/vx-axis/src/utils/toString.ts @@ -0,0 +1,3 @@ +export default function toString(x?: T) { + return x && x.toString(); +} diff --git a/packages/vx-axis/test/Axis.test.tsx b/packages/vx-axis/test/Axis.test.tsx index c727e42ae5..19c2ba20d4 100644 --- a/packages/vx-axis/test/Axis.test.tsx +++ b/packages/vx-axis/test/Axis.test.tsx @@ -3,7 +3,7 @@ import { shallow } from 'enzyme'; import { Line } from '@vx/shape'; import { Text } from '@vx/text'; -import { scaleBand, scaleLinear } from '../../vx-scale/src/index.ts'; +import { scaleBand, scaleLinear } from '../../vx-scale/src'; import { Axis } from '../src'; const axisProps = { diff --git a/packages/vx-axis/test/AxisBottom.test.tsx b/packages/vx-axis/test/AxisBottom.test.tsx index cf21de8e6c..3dbc66ee62 100644 --- a/packages/vx-axis/test/AxisBottom.test.tsx +++ b/packages/vx-axis/test/AxisBottom.test.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { scaleLinear } from '../../vx-scale/src/index.ts'; +import { scaleLinear } from '../../vx-scale/src'; import { Axis, AxisBottom } from '../src'; const axisProps = { diff --git a/packages/vx-axis/test/AxisLeft.test.tsx b/packages/vx-axis/test/AxisLeft.test.tsx index 5c98ad8b37..a9a001d41d 100644 --- a/packages/vx-axis/test/AxisLeft.test.tsx +++ b/packages/vx-axis/test/AxisLeft.test.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { scaleLinear } from '../../vx-scale/src/index.ts'; +import { scaleLinear } from '../../vx-scale/src'; import { Axis, AxisLeft } from '../src'; const axisProps = { diff --git a/packages/vx-axis/test/AxisRight.test.tsx b/packages/vx-axis/test/AxisRight.test.tsx index ed6895213b..2d8123bd8f 100644 --- a/packages/vx-axis/test/AxisRight.test.tsx +++ b/packages/vx-axis/test/AxisRight.test.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { scaleLinear } from '../../vx-scale/src/index.ts'; +import { scaleLinear } from '../../vx-scale/src'; import { Axis, AxisRight } from '../src'; const axisProps = { diff --git a/packages/vx-axis/test/AxisTop.test.tsx b/packages/vx-axis/test/AxisTop.test.tsx index b600718788..5695410e2d 100644 --- a/packages/vx-axis/test/AxisTop.test.tsx +++ b/packages/vx-axis/test/AxisTop.test.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { scaleLinear } from '../../vx-scale/src/index.ts'; +import { scaleLinear } from '../../vx-scale/src'; import { Axis, AxisTop } from '../src'; const axisProps = { diff --git a/packages/vx-text/src/Text.tsx b/packages/vx-text/src/Text.tsx index 483bf4f98a..ad2829ee38 100644 --- a/packages/vx-text/src/Text.tsx +++ b/packages/vx-text/src/Text.tsx @@ -21,6 +21,8 @@ interface WordsWithWidth { type SVGTSpanProps = React.SVGAttributes; export type TextProps = { + /** className to apply to the SVGText element. */ + className?: string; /** Whether to scale the fontSize to accomodate the specified width. */ scaleToFit?: boolean; /** Rotational angle of the text. */ From 2860cfc4b0b07c582ee4c0bd66ef00f8e5d2229b Mon Sep 17 00:00:00 2001 From: Chris Williams Date: Fri, 27 Dec 2019 15:26:19 -0800 Subject: [PATCH 04/13] typescript(vx-axis): iterate on types --- packages/vx-axis/package.json | 3 + packages/vx-axis/src/axis/Axis.tsx | 8 +-- packages/vx-axis/src/types.ts | 76 ++++------------------- packages/vx-axis/test/Axis.test.tsx | 13 ++-- packages/vx-axis/test/AxisBottom.test.tsx | 3 +- packages/vx-axis/test/AxisLeft.test.tsx | 3 +- packages/vx-axis/test/AxisRight.test.tsx | 3 +- packages/vx-axis/test/AxisTop.test.tsx | 3 +- packages/vx-text/src/Text.tsx | 7 ++- 9 files changed, 42 insertions(+), 77 deletions(-) diff --git a/packages/vx-axis/package.json b/packages/vx-axis/package.json index 0de96c810e..e65f812eda 100644 --- a/packages/vx-axis/package.json +++ b/packages/vx-axis/package.json @@ -41,6 +41,9 @@ "classnames": "^2.2.5", "prop-types": "^15.6.0" }, + "devDependencies": { + "@vx/scale": "0.0.192" + }, "peerDependencies": { "react": "^16.3.0-0" }, diff --git a/packages/vx-axis/src/axis/Axis.tsx b/packages/vx-axis/src/axis/Axis.tsx index ed9c54f2bf..0a52d6f20e 100644 --- a/packages/vx-axis/src/axis/Axis.tsx +++ b/packages/vx-axis/src/axis/Axis.tsx @@ -29,14 +29,14 @@ export default function Axis({ textAnchor: 'middle', fontFamily: 'Arial', fontSize: 10, - fill: 'black', + fill: '#222', }, left = 0, numTicks = 10, orientation = ORIENT.bottom, rangePadding = 0, scale, - stroke = 'black', + stroke = '#222', strokeWidth = 1, strokeDasharray, tickClassName, @@ -45,10 +45,10 @@ export default function Axis({ textAnchor: 'middle', fontFamily: 'Arial', fontSize: 10, - fill: 'black', + fill: '#222', }), tickLength = 8, - tickStroke = 'black', + tickStroke = '#222', tickTransform, tickValues, tickComponent, diff --git a/packages/vx-axis/src/types.ts b/packages/vx-axis/src/types.ts index 738c45d287..89570e3901 100644 --- a/packages/vx-axis/src/types.ts +++ b/packages/vx-axis/src/types.ts @@ -4,17 +4,17 @@ export type AxisOrientation = 'top' | 'right' | 'bottom' | 'left'; type Output = number; -export type FormattedValue = string | undefined; +export type FormattedValue = string | number | undefined; export type TickFormatter = (value: Input, tickIndex: number) => FormattedValue; export type TickLabelProps = (val: Input, index: number) => Partial; -export type TickRendererProps = { +export type TickRendererProps = Partial & { x: number; y: number; formattedValue: FormattedValue; -} & Omit, 'x' | 'y'>; +}; export type SharedAxisProps = { /** The class name applied to the outermost axis group element. */ @@ -24,9 +24,9 @@ export type SharedAxisProps = { /** If true, will hide the axis line. */ hideAxisLine?: boolean; /** If true, will hide the ticks (but not the tick labels). */ - hideTicks: boolean; + hideTicks?: boolean; /** If true, will hide the '0' value tick and tick label. */ - hideZero: boolean; + hideZero?: boolean; /** The text for the axis label. */ label?: string; /** The class name applied to the axis label text element. */ @@ -34,7 +34,7 @@ export type SharedAxisProps = { /** Pixel offset of the axis label (does not include tick label font size, which is accounted for automatically) */ labelOffset?: number; /** Props applied to the axis label component. */ - labelProps?: {}; + labelProps?: Partial; /** A left pixel offset applied to the entire axis. */ left?: number; /** The number of ticks wanted for the axis (note this is approximate) */ @@ -52,9 +52,9 @@ export type SharedAxisProps = { /** The class name applied to each tick group. */ tickClassName?: string; /** A [d3 formatter](https://github.com/d3/d3-scale/blob/master/README.md#continuous_tickFormat) for the tick text. */ - tickFormat: TickFormatter; + tickFormat?: TickFormatter; /** A function that returns props for a given tick label. */ - tickLabelProps: TickLabelProps; + tickLabelProps?: TickLabelProps; /** The length of the tick lines. */ tickLength?: number; /** The color for the tick's stroke value. */ @@ -62,21 +62,19 @@ export type SharedAxisProps = { /** A custom SVG transform value to be applied to each tick group. */ tickTransform?: string; /** An array of values that determine the number and values of the ticks. Falls back to `scale.ticks()` or `.domain()`. */ - tickValues: Input[]; + tickValues?: Input[]; /** */ - tickComponent: (tickRendererProps: TickRendererProps) => React.ReactNode; + tickComponent?: (tickRendererProps: TickRendererProps) => React.ReactNode; /** A top pixel offset applied to the entire axis. */ top?: number; /** For more control over rendering or to add event handlers to datum, pass a function as children. */ - children: (renderProps: ChildRenderProps) => React.ReactNode; + children?: (renderProps: ChildRenderProps) => React.ReactNode; }; -export interface GenericScale { +export interface GenericScale { (value: Input): Output; - domain(input: Input[]): this; domain(): Input[] | [Input, Input]; range(): Output[] | [Output, Output]; - range(output: Output[]): this; ticks?: (count: number) => Input[] | [Input, Input]; bandwidth?: () => number; round?: () => boolean; @@ -106,54 +104,6 @@ export type ChildRenderProps = { index: number; from: Point; to: Point; - formattedValue: Input | string | undefined | null; + formattedValue: FormattedValue; }[]; - // ticks: values.map((value, index) => { - // const from = new Point({ - // x: horizontal ? position(value) : 0, - // y: horizontal ? 0 : position(value), - // }); - // const to = new Point({ - // x: horizontal ? position(value) : tickSign * tickLength, - // y: horizontal ? tickLength * tickSign : position(value), - // }); - // return { - // value, - // index, - // from, - // to, - // formattedValue: format(value, index), - // }; - // }), }; - -// eslint doesn't know about @types/d3-scale -// eslint-disable-next-line import/no-extraneous-dependencies -// import { -// ScaleBand, -// ScaleLinear, -// ScaleLogarithmic, -// ScaleOrdinal, -// ScaleQuantile, -// ScaleQuantize, -// ScaleThreshold, -// ScalePower, -// ScaleTime, -// } from 'd3-scale'; - -// numberic domain -// export type ScaleType< -// Input = unknown, -// Output = unknown, -// > = -// | ScaleBand -// | ScaleLinear -// | ScaleLogarithmic -// | ScaleOrdinal -// | ScaleQuantile -// | ScaleQuantize -// | ScaleThreshold; - -// export type ScaleType = S extends ScaleBand -// ? ScaleBandScaleBand -// : ScaleLinear; diff --git a/packages/vx-axis/test/Axis.test.tsx b/packages/vx-axis/test/Axis.test.tsx index 19c2ba20d4..7519f32cd2 100644 --- a/packages/vx-axis/test/Axis.test.tsx +++ b/packages/vx-axis/test/Axis.test.tsx @@ -3,15 +3,16 @@ import { shallow } from 'enzyme'; import { Line } from '@vx/shape'; import { Text } from '@vx/text'; -import { scaleBand, scaleLinear } from '../../vx-scale/src'; +import { scaleBand, scaleLinear } from '@vx/scale'; import { Axis } from '../src'; +import { AxisOrientation, GenericScale } from '../src/types'; const axisProps = { - orientation: 'left', + orientation: 'left' as AxisOrientation, scale: scaleLinear({ rangeRound: [10, 0], domain: [0, 10], - }), + }) as GenericScale, label: 'test axis', }; @@ -184,7 +185,9 @@ describe('', () => { }); test('tickFormat should have access to tick index', () => { - const wrapper = shallow( i} />); + const wrapper = shallow( + `${i}`} />, + ); expect( wrapper .children() @@ -198,7 +201,7 @@ describe('', () => { const overrideAxisProps = { scale: scaleBand({ rangeRound: [10, 0], - domain: [0, 10], + domain: ['a', 'b', 'c'], }), }; const wrapper = shallow(); diff --git a/packages/vx-axis/test/AxisBottom.test.tsx b/packages/vx-axis/test/AxisBottom.test.tsx index 3dbc66ee62..e5c8066d39 100644 --- a/packages/vx-axis/test/AxisBottom.test.tsx +++ b/packages/vx-axis/test/AxisBottom.test.tsx @@ -3,12 +3,13 @@ import { shallow } from 'enzyme'; import { scaleLinear } from '../../vx-scale/src'; import { Axis, AxisBottom } from '../src'; +import { GenericScale } from '../src/types'; const axisProps = { scale: scaleLinear({ rangeRound: [10, 0], domain: [0, 10], - }), + }) as GenericScale, }; describe('', () => { diff --git a/packages/vx-axis/test/AxisLeft.test.tsx b/packages/vx-axis/test/AxisLeft.test.tsx index a9a001d41d..f9256a954d 100644 --- a/packages/vx-axis/test/AxisLeft.test.tsx +++ b/packages/vx-axis/test/AxisLeft.test.tsx @@ -3,12 +3,13 @@ import { shallow } from 'enzyme'; import { scaleLinear } from '../../vx-scale/src'; import { Axis, AxisLeft } from '../src'; +import { GenericScale } from '../src/types'; const axisProps = { scale: scaleLinear({ rangeRound: [10, 0], domain: [0, 10], - }), + }) as GenericScale, }; describe('', () => { diff --git a/packages/vx-axis/test/AxisRight.test.tsx b/packages/vx-axis/test/AxisRight.test.tsx index 2d8123bd8f..07b04aa7f4 100644 --- a/packages/vx-axis/test/AxisRight.test.tsx +++ b/packages/vx-axis/test/AxisRight.test.tsx @@ -3,12 +3,13 @@ import { shallow } from 'enzyme'; import { scaleLinear } from '../../vx-scale/src'; import { Axis, AxisRight } from '../src'; +import { GenericScale } from '../src/types'; const axisProps = { scale: scaleLinear({ rangeRound: [10, 0], domain: [0, 10], - }), + }) as GenericScale, }; describe('', () => { diff --git a/packages/vx-axis/test/AxisTop.test.tsx b/packages/vx-axis/test/AxisTop.test.tsx index 5695410e2d..b26285cf07 100644 --- a/packages/vx-axis/test/AxisTop.test.tsx +++ b/packages/vx-axis/test/AxisTop.test.tsx @@ -3,12 +3,13 @@ import { shallow } from 'enzyme'; import { scaleLinear } from '../../vx-scale/src'; import { Axis, AxisTop } from '../src'; +import { GenericScale } from '../src/types'; const axisProps = { scale: scaleLinear({ rangeRound: [10, 0], domain: [0, 10], - }), + }) as GenericScale, }; describe('', () => { diff --git a/packages/vx-text/src/Text.tsx b/packages/vx-text/src/Text.tsx index ad2829ee38..db8592d53b 100644 --- a/packages/vx-text/src/Text.tsx +++ b/packages/vx-text/src/Text.tsx @@ -19,6 +19,7 @@ interface WordsWithWidth { } type SVGTSpanProps = React.SVGAttributes; +type SVGTextProps = React.SVGAttributes; export type TextProps = { /** className to apply to the SVGText element. */ @@ -48,7 +49,11 @@ export type TextProps = { /** Cap height of the text. */ capHeight?: SVGTSpanProps['capHeight']; /** Font size of text. */ - fontSize?: SVGTSpanProps['fontSize']; + fontSize?: SVGTextProps['fontSize']; + /** Font family of text. */ + fontFamily?: SVGTextProps['fontFamily']; + /** Fill color of text. */ + fill?: SVGTextProps['fill']; /** Maximum width to occupy (approximate as words are not split). */ width?: number; /** String (or number coercible to one) to be styled and positioned. */ From c42d7afef99db78f01392b75e906663f6ac04648 Mon Sep 17 00:00:00 2001 From: Chris Williams Date: Sat, 28 Dec 2019 16:23:37 -0800 Subject: [PATCH 05/13] typescript(vx-axis): iterate on types more --- packages/vx-axis/src/axis/Axis.tsx | 33 ++-- packages/vx-axis/src/axis/AxisBottom.tsx | 6 +- packages/vx-axis/src/axis/AxisLeft.tsx | 6 +- packages/vx-axis/src/axis/AxisRight.tsx | 6 +- packages/vx-axis/src/axis/AxisTop.tsx | 6 +- packages/vx-axis/src/types.ts | 54 +++--- packages/vx-axis/src/utils/center.ts | 4 +- packages/vx-axis/src/utils/labelTransform.ts | 8 +- .../vx-axis/src/utils/toNumberOrUndefined.ts | 6 + packages/vx-axis/test/scales.test.tsx | 161 ++++++++++++++++++ 10 files changed, 236 insertions(+), 54 deletions(-) create mode 100644 packages/vx-axis/src/utils/toNumberOrUndefined.ts create mode 100644 packages/vx-axis/test/scales.test.tsx diff --git a/packages/vx-axis/src/axis/Axis.tsx b/packages/vx-axis/src/axis/Axis.tsx index 0a52d6f20e..f9e1b7b2ab 100644 --- a/packages/vx-axis/src/axis/Axis.tsx +++ b/packages/vx-axis/src/axis/Axis.tsx @@ -3,19 +3,20 @@ import cx from 'classnames'; import { Line } from '@vx/shape'; import { Point } from '@vx/point'; import { Group } from '@vx/group'; -import { Text } from '@vx/text'; +import Text from '@vx/text/lib/Text'; import center from '../utils/center'; import identity from '../utils/identity'; import getLabelTransform from '../utils/labelTransform'; import ORIENT from '../constants/orientation'; import toString from '../utils/toString'; +import toNumberOrUndefined from '../utils/toNumberOrUndefined'; import { SharedAxisProps, AxisOrientation, TickFormatter } from '../types'; -export type AxisProps = SharedAxisProps & { +export type AxisProps = SharedAxisProps & { orientation: AxisOrientation; }; -export default function Axis({ +export default function Axis({ children, axisClassName, axisLineClassName, @@ -53,15 +54,15 @@ export default function Axis({ tickValues, tickComponent, top = 0, -}: AxisProps) { +}: AxisProps) { let values = scale.ticks ? scale.ticks(numTicks) : scale.domain(); if (tickValues) values = tickValues; - let format: TickFormatter = scale.tickFormat ? scale.tickFormat() : toString; + let format: TickFormatter = scale.tickFormat ? scale.tickFormat() : toString; if (tickFormat) format = tickFormat; const range = scale.range(); - const range0 = range[0] + 0.5 - rangePadding; - const range1 = range[range.length - 1] + 0.5 + rangePadding; + const range0 = Number(range[0]) + 0.5 - rangePadding; + const range1 = Number(range[range.length - 1]) + 0.5 + rangePadding; const horizontal = orientation !== ORIENT.left && orientation !== ORIENT.right; const isLeft = orientation === ORIENT.left; @@ -96,13 +97,14 @@ export default function Axis({ tickFormat: format, tickPosition: position, ticks: values.map((value, index) => { + const scaledValue = toNumberOrUndefined(position(value)); const from = new Point({ - x: horizontal ? position(value) : 0, - y: horizontal ? 0 : position(value), + x: horizontal ? scaledValue : 0, + y: horizontal ? 0 : scaledValue, }); const to = new Point({ - x: horizontal ? position(value) : tickSign * tickLength, - y: horizontal ? tickLength * tickSign : position(value), + x: horizontal ? scaledValue : tickSign * tickLength, + y: horizontal ? tickLength * tickSign : scaledValue, }); return { value, @@ -126,13 +128,14 @@ export default function Axis({ ) { return null; } + const scaledValue = toNumberOrUndefined(position(val)); const tickFromPoint = new Point({ - x: horizontal ? position(val) : 0, - y: horizontal ? 0 : position(val), + x: horizontal ? scaledValue : 0, + y: horizontal ? 0 : scaledValue, }); const tickToPoint = new Point({ - x: horizontal ? position(val) : tickSign * tickLength, - y: horizontal ? tickLength * tickSign : position(val), + x: horizontal ? scaledValue : tickSign * tickLength, + y: horizontal ? tickLength * tickSign : scaledValue, }); const tickLabelPropsObj = tickLabelProps(val, index); diff --git a/packages/vx-axis/src/axis/AxisBottom.tsx b/packages/vx-axis/src/axis/AxisBottom.tsx index 930632f97c..dd146562a8 100644 --- a/packages/vx-axis/src/axis/AxisBottom.tsx +++ b/packages/vx-axis/src/axis/AxisBottom.tsx @@ -4,9 +4,9 @@ import Axis from './Axis'; import ORIENT from '../constants/orientation'; import { SharedAxisProps } from '../types'; -export type AxisBottomProps = SharedAxisProps; +export type AxisBottomProps = SharedAxisProps; -export default function AxisBottom({ +export default function AxisBottom({ children, axisClassName, axisLineClassName, @@ -39,7 +39,7 @@ export default function AxisBottom({ tickValues, tickComponent, top, -}: AxisBottomProps) { +}: AxisBottomProps) { return ( = SharedAxisProps; +export type AxisLeftProps = SharedAxisProps; -export default function AxisLeft({ +export default function AxisLeft({ children, axisClassName, axisLineClassName, @@ -40,7 +40,7 @@ export default function AxisLeft({ tickValues, tickComponent, top, -}: AxisLeftProps) { +}: AxisLeftProps) { return ( = SharedAxisProps; +export type AxisRightProps = SharedAxisProps; -export default function AxisRight({ +export default function AxisRight({ children, axisClassName, axisLineClassName, @@ -40,7 +40,7 @@ export default function AxisRight({ tickValues, tickComponent, top, -}: AxisRightProps) { +}: AxisRightProps) { return ( = SharedAxisProps; +export type AxisTopProps = SharedAxisProps; -export default function AxisTop({ +export default function AxisTop({ children, axisClassName, axisLineClassName, @@ -39,7 +39,7 @@ export default function AxisTop({ tickValues, tickComponent, top, -}: AxisTopProps) { +}: AxisTopProps) { return ( = (value: Input, tickIndex: number) => FormattedValue; +export type TickFormatter = (value: ScaleInput, tickIndex: number) => FormattedValue; -export type TickLabelProps = (val: Input, index: number) => Partial; +export type TickLabelProps = (val: ScaleInput, index: number) => Partial; export type TickRendererProps = Partial & { x: number; @@ -16,7 +14,7 @@ export type TickRendererProps = Partial & { formattedValue: FormattedValue; }; -export type SharedAxisProps = { +export type SharedAxisProps = { /** The class name applied to the outermost axis group element. */ axisClassName?: string; /** The class name applied to the axis line element. */ @@ -42,7 +40,7 @@ export type SharedAxisProps = { /** Pixel padding to apply to both sides of the axis. */ rangePadding?: number; /** A [d3](https://github.com/d3/d3-scale) or [vx](https://github.com/hshoff/vx/tree/master/packages/vx-scale) scale function. */ - scale: GenericScale; + scale: GenericScale; /** The color for the stroke of the lines. */ stroke?: string; /** The pixel value for the width of the lines. */ @@ -52,9 +50,9 @@ export type SharedAxisProps = { /** The class name applied to each tick group. */ tickClassName?: string; /** A [d3 formatter](https://github.com/d3/d3-scale/blob/master/README.md#continuous_tickFormat) for the tick text. */ - tickFormat?: TickFormatter; + tickFormat?: TickFormatter; /** A function that returns props for a given tick label. */ - tickLabelProps?: TickLabelProps; + tickLabelProps?: TickLabelProps; /** The length of the tick lines. */ tickLength?: number; /** The color for the tick's stroke value. */ @@ -62,32 +60,46 @@ export type SharedAxisProps = { /** A custom SVG transform value to be applied to each tick group. */ tickTransform?: string; /** An array of values that determine the number and values of the ticks. Falls back to `scale.ticks()` or `.domain()`. */ - tickValues?: Input[]; + tickValues?: ScaleInput[]; /** */ - tickComponent?: (tickRendererProps: TickRendererProps) => React.ReactNode; + tickComponent?: (tickRendererProps: TickRendererProps) => React.ReactNode; /** A top pixel offset applied to the entire axis. */ top?: number; /** For more control over rendering or to add event handlers to datum, pass a function as children. */ - children?: (renderProps: ChildRenderProps) => React.ReactNode; + children?: (renderProps: ChildRenderProps) => React.ReactNode; }; -export interface GenericScale { - (value: Input): Output; - domain(): Input[] | [Input, Input]; - range(): Output[] | [Output, Output]; - ticks?: (count: number) => Input[] | [Input, Input]; +/** In order to plot values on an axis, Output must be numeric. */ +export type ScaleOutput = number | { valueOf(): number } | undefined; + +export type GenericScale = + | ScaleNoRangeRound + | ScaleWithRangeRound; + +interface ScaleNoRangeRound { + (value: ScaleInput): ScaleOutput; + domain(): ScaleInput[] | [ScaleInput, ScaleInput]; + domain(scaleInput: ScaleInput[] | [ScaleInput, ScaleInput]): this; + range(): ScaleOutput[] | [ScaleOutput, ScaleOutput]; + range(scaleOutput: ScaleOutput[] | [ScaleOutput, ScaleOutput]): this; + ticks?: (count: number) => ScaleInput[] | [ScaleInput, ScaleInput]; bandwidth?: () => number; round?: () => boolean; - tickFormat?: () => (input: Input) => FormattedValue; + tickFormat?: () => (input: ScaleInput) => FormattedValue; copy(): this; } +interface ScaleWithRangeRound extends ScaleNoRangeRound { + rangeRound(): ScaleOutput[] | [ScaleOutput, ScaleOutput]; + rangeRound(scaleOutput: ScaleOutput[] | [ScaleOutput, ScaleOutput]): this; +} + export interface Point { x: number; y: number; } -export type ChildRenderProps = { +export type ChildRenderProps = { axisFromPoint: Point; axisToPoint: Point; horizontal: boolean; @@ -97,10 +109,10 @@ export type ChildRenderProps = { label?: string; rangePadding: number; tickLength: number; - tickFormat: TickFormatter; - tickPosition: (value: Input) => Output; + tickFormat: TickFormatter; + tickPosition: (value: ScaleInput) => ScaleOutput; ticks: { - value: Input; + value: ScaleInput; index: number; from: Point; to: Point; diff --git a/packages/vx-axis/src/utils/center.ts b/packages/vx-axis/src/utils/center.ts index c0f0804821..2439d8c3e8 100644 --- a/packages/vx-axis/src/utils/center.ts +++ b/packages/vx-axis/src/utils/center.ts @@ -4,12 +4,12 @@ import { GenericScale } from '../types'; * Returns a function that applies a centering transform to a scaled value, * if `Output` is of type `number` and `scale.bandwidth()` is defined */ -export default function center(scale: GenericScale) { +export default function center(scale: GenericScale) { let offset = scale.bandwidth ? scale.bandwidth() / 2 : 0; if (scale.round && scale.round()) offset = Math.round(offset); - return (d: Input) => { + return (d: ScaleInput) => { const scaledValue = scale(d); return typeof scaledValue === 'number' ? scaledValue + offset : scaledValue; }; diff --git a/packages/vx-axis/src/utils/labelTransform.ts b/packages/vx-axis/src/utils/labelTransform.ts index 8147b11b0c..ce964d543b 100644 --- a/packages/vx-axis/src/utils/labelTransform.ts +++ b/packages/vx-axis/src/utils/labelTransform.ts @@ -1,12 +1,12 @@ import { TextProps } from '@vx/text/lib/Text'; import ORIENT from '../constants/orientation'; -import { AxisOrientation } from '../types'; +import { AxisOrientation, ScaleOutput } from '../types'; export interface TransformArgs { labelOffset: number; labelProps: Partial; orientation: AxisOrientation; - range: number[]; + range: ScaleOutput[]; tickLabelFontSize: number; tickLength: number; } @@ -31,10 +31,10 @@ export default function labelTransform({ ? labelProps.fontSize : 0; - x = (range[0] + range[range.length - 1]) / 2; + x = (Number(range[0]) + Number(range[range.length - 1])) / 2; y = sign * (tickLength + labelOffset + tickLabelFontSize + yBottomOffset); } else { - x = sign * ((range[0] + range[range.length - 1]) / 2); + x = sign * ((Number(range[0]) + Number(range[range.length - 1])) / 2); y = -(tickLength + labelOffset); transform = `rotate(${sign * 90})`; } diff --git a/packages/vx-axis/src/utils/toNumberOrUndefined.ts b/packages/vx-axis/src/utils/toNumberOrUndefined.ts new file mode 100644 index 0000000000..46beaafe02 --- /dev/null +++ b/packages/vx-axis/src/utils/toNumberOrUndefined.ts @@ -0,0 +1,6 @@ +export default function toNumberOrUndefined( + val?: number | { valueOf(): number }, +): number | undefined { + if (typeof val === 'undefined') return val; + return Number(val); +} diff --git a/packages/vx-axis/test/scales.test.tsx b/packages/vx-axis/test/scales.test.tsx new file mode 100644 index 0000000000..2eed5bcd5b --- /dev/null +++ b/packages/vx-axis/test/scales.test.tsx @@ -0,0 +1,161 @@ +import React from 'react'; +import { shallow } from 'enzyme'; +import { + scaleBand, + scaleLinear, + scaleLog, + scaleOrdinal, + scalePoint, + scalePower, + scaleQuantile, + scaleQuantize, + scaleSymlog, + scaleThreshold, + scaleTime, + scaleUtc, +} from '@vx/scale'; +import { Axis } from '../src'; +import { GenericScale, AxisOrientation } from '../src/types'; + +const axisProps = { + orientation: 'left' as AxisOrientation, + label: 'test axis', +}; + +function setup(scale: GenericScale) { + return () => shallow(); +} + +describe('Axis scales', () => { + it('should render with scaleBand', () => { + expect( + setup( + scaleBand({ + rangeRound: [10, 0], + domain: ['a', 'b', 'c'], + }) as GenericScale, + ), + ).not.toThrow(); + }); + + it('should render with scaleLinear', () => { + expect( + setup( + scaleLinear({ + rangeRound: [10, 0], + domain: [0, 10], + }) as GenericScale, + ), + ).not.toThrow(); + }); + + it('should render with scaleLog', () => { + expect( + setup( + scaleLog({ + rangeRound: [10, 0], + domain: [1, 10, 100, 1000], + }) as GenericScale, + ), + ).not.toThrow(); + }); + + it('should render with scaleOrdinal', () => { + expect( + setup( + scaleOrdinal({ + range: [0, 10], + domain: ['a', 'b', 'c'], + }) as GenericScale, + ), + ).not.toThrow(); + }); + + it('should render with scalePoint', () => { + expect( + setup( + scalePoint({ + rangeRound: [0, 10], + domain: ['a', 'b', 'c'], + }) as GenericScale, + ), + ).not.toThrow(); + }); + + it('should render with scalePower', () => { + expect( + setup( + scalePower({ + range: [1, 2, 3, 4, 5], + domain: [1, 10, 100, 1000, 10000], + }) as GenericScale, + ), + ).not.toThrow(); + }); + + it('should render with scaleQuantile', () => { + expect( + setup( + scaleQuantile({ + range: [0, 2, 4, 6, 8, 10], + domain: [1, 10, 100, 1000, 10000], + }) as GenericScale, + ), + ).not.toThrow(); + }); + + // it('should render with scaleQuantize', () => { + // expect( + // setup( + // scaleQuantize({ + // range: [new Date('2020-01-01'), new Date('2020-01-02')], + // domain: [1, 10], + // }) as GenericScale, + // ), + // ).not.toThrow(); + // }); + + it('should render with scaleSymlog', () => { + expect( + setup( + scaleSymlog({ + range: [1, 10], + domain: [1, 10], + }) as GenericScale, + ), + ).not.toThrow(); + }); + + it('should render with scaleThreshold', () => { + expect( + setup( + scaleThreshold({ + range: [1, 10], + domain: [1, 10], + }) as GenericScale, + ), + ).not.toThrow(); + }); + + it('should render with scaleTime', () => { + expect( + setup( + scaleTime({ + range: [1, 10], + domain: [new Date('2020-01-01'), new Date('2020-01-05')], + }) as GenericScale, + ), + ).not.toThrow(); + }); + + it('should render with scaleUtc', () => { + expect( + setup( + scaleUtc({ + range: [1, 10], + domain: [new Date('2020-01-01'), new Date('2020-01-05')], + }) as GenericScale, + ), + ).not.toThrow(); + }); +}); From 97bc2af84104d1f34b44f6b813782c22b2e75c12 Mon Sep 17 00:00:00 2001 From: Chris Williams Date: Sat, 28 Dec 2019 16:45:19 -0800 Subject: [PATCH 06/13] typescript(vx-axis): iterate on types --- packages/vx-axis/src/axis/Axis.tsx | 3 +-- packages/vx-axis/src/types.ts | 6 ++++-- packages/vx-axis/src/utils/center.ts | 6 ++++-- packages/vx-axis/src/utils/identity.ts | 3 --- packages/vx-axis/test/Axis.test.tsx | 5 +++-- packages/vx-axis/test/scales.test.tsx | 24 ++++++++++++------------ 6 files changed, 24 insertions(+), 23 deletions(-) delete mode 100644 packages/vx-axis/src/utils/identity.ts diff --git a/packages/vx-axis/src/axis/Axis.tsx b/packages/vx-axis/src/axis/Axis.tsx index f9e1b7b2ab..f202c3121c 100644 --- a/packages/vx-axis/src/axis/Axis.tsx +++ b/packages/vx-axis/src/axis/Axis.tsx @@ -5,7 +5,6 @@ import { Point } from '@vx/point'; import { Group } from '@vx/group'; import Text from '@vx/text/lib/Text'; import center from '../utils/center'; -import identity from '../utils/identity'; import getLabelTransform from '../utils/labelTransform'; import ORIENT from '../constants/orientation'; import toString from '../utils/toString'; @@ -69,7 +68,7 @@ export default function Axis({ const isTop = orientation === ORIENT.top; const tickSign = isLeft || isTop ? -1 : 1; - const position = (scale.bandwidth ? center : identity)(scale.copy()); + const position = center(scale.copy()); const axisFromPoint = new Point({ x: horizontal ? range0 : 0, diff --git a/packages/vx-axis/src/types.ts b/packages/vx-axis/src/types.ts index 4dd239e8bc..e3ab4255df 100644 --- a/packages/vx-axis/src/types.ts +++ b/packages/vx-axis/src/types.ts @@ -69,7 +69,8 @@ export type SharedAxisProps = { children?: (renderProps: ChildRenderProps) => React.ReactNode; }; -/** In order to plot values on an axis, Output must be numeric. */ +// In order to plot values on an axis, Output must be numeric or coercible to a number. +// Some scales return undefined. export type ScaleOutput = number | { valueOf(): number } | undefined; export type GenericScale = @@ -77,7 +78,7 @@ export type GenericScale = | ScaleWithRangeRound; interface ScaleNoRangeRound { - (value: ScaleInput): ScaleOutput; + (value: ScaleInput): ScaleOutput | [ScaleOutput, ScaleOutput]; // quantize scales return an array domain(): ScaleInput[] | [ScaleInput, ScaleInput]; domain(scaleInput: ScaleInput[] | [ScaleInput, ScaleInput]): this; range(): ScaleOutput[] | [ScaleOutput, ScaleOutput]; @@ -89,6 +90,7 @@ interface ScaleNoRangeRound { copy(): this; } +// We cannot have optional methods AND overloads, so define a separate type for rangeRound interface ScaleWithRangeRound extends ScaleNoRangeRound { rangeRound(): ScaleOutput[] | [ScaleOutput, ScaleOutput]; rangeRound(scaleOutput: ScaleOutput[] | [ScaleOutput, ScaleOutput]): this; diff --git a/packages/vx-axis/src/utils/center.ts b/packages/vx-axis/src/utils/center.ts index 2439d8c3e8..83683be4c4 100644 --- a/packages/vx-axis/src/utils/center.ts +++ b/packages/vx-axis/src/utils/center.ts @@ -6,11 +6,13 @@ import { GenericScale } from '../types'; */ export default function center(scale: GenericScale) { let offset = scale.bandwidth ? scale.bandwidth() / 2 : 0; - if (scale.round && scale.round()) offset = Math.round(offset); return (d: ScaleInput) => { const scaledValue = scale(d); - return typeof scaledValue === 'number' ? scaledValue + offset : scaledValue; + if (typeof scaledValue === 'number') return scaledValue + offset; + // quantize scales return an array of values + if (Array.isArray(scaledValue)) return Number(scaledValue[0]) + offset; + return scaledValue; }; } diff --git a/packages/vx-axis/src/utils/identity.ts b/packages/vx-axis/src/utils/identity.ts deleted file mode 100644 index 5538f47174..0000000000 --- a/packages/vx-axis/src/utils/identity.ts +++ /dev/null @@ -1,3 +0,0 @@ -export default function identity(x: T) { - return x; -} diff --git a/packages/vx-axis/test/Axis.test.tsx b/packages/vx-axis/test/Axis.test.tsx index 7519f32cd2..eefc0513ab 100644 --- a/packages/vx-axis/test/Axis.test.tsx +++ b/packages/vx-axis/test/Axis.test.tsx @@ -5,10 +5,10 @@ import { Line } from '@vx/shape'; import { Text } from '@vx/text'; import { scaleBand, scaleLinear } from '@vx/scale'; import { Axis } from '../src'; -import { AxisOrientation, GenericScale } from '../src/types'; +import { GenericScale } from '../src/types'; const axisProps = { - orientation: 'left' as AxisOrientation, + orientation: 'left' as const, scale: scaleLinear({ rangeRound: [10, 0], domain: [0, 10], @@ -199,6 +199,7 @@ describe('', () => { test('it should use center if scale is band', () => { const overrideAxisProps = { + orientation: 'left' as const, scale: scaleBand({ rangeRound: [10, 0], domain: ['a', 'b', 'c'], diff --git a/packages/vx-axis/test/scales.test.tsx b/packages/vx-axis/test/scales.test.tsx index 2eed5bcd5b..0ce6ba82eb 100644 --- a/packages/vx-axis/test/scales.test.tsx +++ b/packages/vx-axis/test/scales.test.tsx @@ -15,10 +15,10 @@ import { scaleUtc, } from '@vx/scale'; import { Axis } from '../src'; -import { GenericScale, AxisOrientation } from '../src/types'; +import { GenericScale } from '../src/types'; const axisProps = { - orientation: 'left' as AxisOrientation, + orientation: 'left' as const, label: 'test axis', }; @@ -104,16 +104,16 @@ describe('Axis scales', () => { ).not.toThrow(); }); - // it('should render with scaleQuantize', () => { - // expect( - // setup( - // scaleQuantize({ - // range: [new Date('2020-01-01'), new Date('2020-01-02')], - // domain: [1, 10], - // }) as GenericScale, - // ), - // ).not.toThrow(); - // }); + it('should render with scaleQuantize', () => { + expect( + setup( + scaleQuantize({ + range: [1, 10], + domain: [1, 10], + }) as GenericScale, + ), + ).not.toThrow(); + }); it('should render with scaleSymlog', () => { expect( From b9d93ad8fc2e63f192c936627bf1596a8df12f66 Mon Sep 17 00:00:00 2001 From: Chris Williams Date: Sat, 28 Dec 2019 16:52:46 -0800 Subject: [PATCH 07/13] deps(vx-axis): remove @types/d3-scale --- packages/vx-axis/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/vx-axis/package.json b/packages/vx-axis/package.json index e65f812eda..bdbc8a4efc 100644 --- a/packages/vx-axis/package.json +++ b/packages/vx-axis/package.json @@ -32,7 +32,6 @@ "homepage": "https://github.com/hshoff/vx#readme", "dependencies": { "@types/classnames": "^2.2.9", - "@types/d3-scale": "^2.1.1", "@types/react": "*", "@vx/group": "0.0.192", "@vx/point": "0.0.192", From cf202994be1bae847919d36479ea63831f276b1a Mon Sep 17 00:00:00 2001 From: Chris Williams Date: Sat, 28 Dec 2019 22:34:14 -0800 Subject: [PATCH 08/13] fix(vx-axis): fix tests --- packages/vx-axis/src/axis/Axis.tsx | 32 ++++++++++++++--------------- packages/vx-axis/test/Axis.test.tsx | 8 +++----- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/packages/vx-axis/src/axis/Axis.tsx b/packages/vx-axis/src/axis/Axis.tsx index f202c3121c..7890a68689 100644 --- a/packages/vx-axis/src/axis/Axis.tsx +++ b/packages/vx-axis/src/axis/Axis.tsx @@ -12,7 +12,7 @@ import toNumberOrUndefined from '../utils/toNumberOrUndefined'; import { SharedAxisProps, AxisOrientation, TickFormatter } from '../types'; export type AxisProps = SharedAxisProps & { - orientation: AxisOrientation; + orientation?: AxisOrientation; }; export default function Axis({ @@ -63,20 +63,20 @@ export default function Axis({ const range0 = Number(range[0]) + 0.5 - rangePadding; const range1 = Number(range[range.length - 1]) + 0.5 + rangePadding; - const horizontal = orientation !== ORIENT.left && orientation !== ORIENT.right; const isLeft = orientation === ORIENT.left; const isTop = orientation === ORIENT.top; + const axisIsHorizontal = isTop || orientation === ORIENT.bottom; const tickSign = isLeft || isTop ? -1 : 1; const position = center(scale.copy()); const axisFromPoint = new Point({ - x: horizontal ? range0 : 0, - y: horizontal ? 0 : range0, + x: axisIsHorizontal ? range0 : 0, + y: axisIsHorizontal ? 0 : range0, }); const axisToPoint = new Point({ - x: horizontal ? range1 : 0, - y: horizontal ? 0 : range1, + x: axisIsHorizontal ? range1 : 0, + y: axisIsHorizontal ? 0 : range1, }); let tickLabelFontSize = 10; // track the max tick label size to compute label offset @@ -87,7 +87,7 @@ export default function Axis({ {children({ axisFromPoint, axisToPoint, - horizontal, + horizontal: axisIsHorizontal, tickSign, numTicks, label, @@ -98,12 +98,12 @@ export default function Axis({ ticks: values.map((value, index) => { const scaledValue = toNumberOrUndefined(position(value)); const from = new Point({ - x: horizontal ? scaledValue : 0, - y: horizontal ? 0 : scaledValue, + x: axisIsHorizontal ? scaledValue : 0, + y: axisIsHorizontal ? 0 : scaledValue, }); const to = new Point({ - x: horizontal ? scaledValue : tickSign * tickLength, - y: horizontal ? tickLength * tickSign : scaledValue, + x: axisIsHorizontal ? scaledValue : tickSign * tickLength, + y: axisIsHorizontal ? tickLength * tickSign : scaledValue, }); return { value, @@ -129,12 +129,12 @@ export default function Axis({ } const scaledValue = toNumberOrUndefined(position(val)); const tickFromPoint = new Point({ - x: horizontal ? scaledValue : 0, - y: horizontal ? 0 : scaledValue, + x: axisIsHorizontal ? scaledValue : 0, + y: axisIsHorizontal ? 0 : scaledValue, }); const tickToPoint = new Point({ - x: horizontal ? scaledValue : tickSign * tickLength, - y: horizontal ? tickLength * tickSign : scaledValue, + x: axisIsHorizontal ? scaledValue : tickSign * tickLength, + y: axisIsHorizontal ? tickLength * tickSign : scaledValue, }); const tickLabelPropsObj = tickLabelProps(val, index); @@ -143,7 +143,7 @@ export default function Axis({ (typeof tickLabelPropsObj.fontSize === 'number' && tickLabelPropsObj.fontSize) || 0, ); - const tickYCoord = tickToPoint.y + (horizontal && !isTop ? tickLabelFontSize : 0); + const tickYCoord = tickToPoint.y + (axisIsHorizontal && !isTop ? tickLabelFontSize : 0); const formattedValue = format(val, index); return ( ', () => { }); test('tickFormat should have access to tick index', () => { - const wrapper = shallow( - `${i}`} />, - ); + const wrapper = shallow( i} />); expect( wrapper .children() @@ -199,10 +197,10 @@ describe('', () => { test('it should use center if scale is band', () => { const overrideAxisProps = { - orientation: 'left' as const, + orientation: 'bottom' as const, scale: scaleBand({ rangeRound: [10, 0], - domain: ['a', 'b', 'c'], + domain: ['a', 'b'], }), }; const wrapper = shallow(); From 25ed46763457802cf96002d2a63262cdbf2de642 Mon Sep 17 00:00:00 2001 From: Chris Williams Date: Sun, 29 Dec 2019 14:18:46 -0800 Subject: [PATCH 09/13] fix(vx-axis): remove deep import --- packages/vx-axis/src/axis/Axis.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vx-axis/src/axis/Axis.tsx b/packages/vx-axis/src/axis/Axis.tsx index 7890a68689..c953c706f5 100644 --- a/packages/vx-axis/src/axis/Axis.tsx +++ b/packages/vx-axis/src/axis/Axis.tsx @@ -3,7 +3,7 @@ import cx from 'classnames'; import { Line } from '@vx/shape'; import { Point } from '@vx/point'; import { Group } from '@vx/group'; -import Text from '@vx/text/lib/Text'; +import { Text } from '@vx/text'; import center from '../utils/center'; import getLabelTransform from '../utils/labelTransform'; import ORIENT from '../constants/orientation'; From a9f9de8a63b219af4adcd208e067d70a84b42e2b Mon Sep 17 00:00:00 2001 From: Chris Williams Date: Sun, 29 Dec 2019 14:23:18 -0800 Subject: [PATCH 10/13] style(vx-axis): black => #222 --- packages/vx-axis/src/axis/AxisBottom.tsx | 2 +- packages/vx-axis/src/axis/AxisLeft.tsx | 2 +- packages/vx-axis/src/axis/AxisRight.tsx | 2 +- packages/vx-axis/src/axis/AxisTop.tsx | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/vx-axis/src/axis/AxisBottom.tsx b/packages/vx-axis/src/axis/AxisBottom.tsx index dd146562a8..3bde70bdb2 100644 --- a/packages/vx-axis/src/axis/AxisBottom.tsx +++ b/packages/vx-axis/src/axis/AxisBottom.tsx @@ -28,7 +28,7 @@ export default function AxisBottom({ tickFormat, tickLabelProps = (/** tickValue, index */) => ({ dy: '0.25em', - fill: 'black', + fill: '#222', fontFamily: 'Arial', fontSize: 10, textAnchor: 'middle', diff --git a/packages/vx-axis/src/axis/AxisLeft.tsx b/packages/vx-axis/src/axis/AxisLeft.tsx index b915f9aba5..061bf7f92a 100644 --- a/packages/vx-axis/src/axis/AxisLeft.tsx +++ b/packages/vx-axis/src/axis/AxisLeft.tsx @@ -29,7 +29,7 @@ export default function AxisLeft({ tickLabelProps = (/** tickValue, index */) => ({ dx: '-0.25em', dy: '0.25em', - fill: 'black', + fill: '#222', fontFamily: 'Arial', fontSize: 10, textAnchor: 'end', diff --git a/packages/vx-axis/src/axis/AxisRight.tsx b/packages/vx-axis/src/axis/AxisRight.tsx index bec95c0b77..510d36ee08 100644 --- a/packages/vx-axis/src/axis/AxisRight.tsx +++ b/packages/vx-axis/src/axis/AxisRight.tsx @@ -29,7 +29,7 @@ export default function AxisRight({ tickLabelProps = (/** tickValue, index */) => ({ dx: '0.25em', dy: '0.25em', - fill: 'black', + fill: '#222', fontFamily: 'Arial', fontSize: 10, textAnchor: 'start', diff --git a/packages/vx-axis/src/axis/AxisTop.tsx b/packages/vx-axis/src/axis/AxisTop.tsx index b9498d6eaf..0c63024203 100644 --- a/packages/vx-axis/src/axis/AxisTop.tsx +++ b/packages/vx-axis/src/axis/AxisTop.tsx @@ -28,7 +28,7 @@ export default function AxisTop({ tickFormat, tickLabelProps = (/** tickValue, index */) => ({ dy: '-0.25em', - fill: 'black', + fill: '#222', fontFamily: 'Arial', fontSize: 10, textAnchor: 'middle', From 7881e5f3e20f6444082624d6669b4c2e93d7c8d6 Mon Sep 17 00:00:00 2001 From: Chris Williams Date: Sun, 29 Dec 2019 14:31:39 -0800 Subject: [PATCH 11/13] internal(vx-axis): refactor logic to remove lets --- packages/vx-axis/src/axis/Axis.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/vx-axis/src/axis/Axis.tsx b/packages/vx-axis/src/axis/Axis.tsx index c953c706f5..40eb0f301d 100644 --- a/packages/vx-axis/src/axis/Axis.tsx +++ b/packages/vx-axis/src/axis/Axis.tsx @@ -54,10 +54,8 @@ export default function Axis({ tickComponent, top = 0, }: AxisProps) { - let values = scale.ticks ? scale.ticks(numTicks) : scale.domain(); - if (tickValues) values = tickValues; - let format: TickFormatter = scale.tickFormat ? scale.tickFormat() : toString; - if (tickFormat) format = tickFormat; + const values = tickValues || (scale.ticks ? scale.ticks(numTicks) : scale.domain()); + const format = tickFormat || (scale.tickFormat ? scale.tickFormat() : toString); const range = scale.range(); const range0 = Number(range[0]) + 0.5 - rangePadding; From f2cfccf08dd0968353c9b0e95816d1a91e219281 Mon Sep 17 00:00:00 2001 From: Chris Williams Date: Sun, 29 Dec 2019 14:36:37 -0800 Subject: [PATCH 12/13] docs(vx-axis): add missing doc string for tickComponent --- packages/vx-axis/src/types.ts | 44 +++++++++++++++++------------------ 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/packages/vx-axis/src/types.ts b/packages/vx-axis/src/types.ts index e3ab4255df..f766db892b 100644 --- a/packages/vx-axis/src/types.ts +++ b/packages/vx-axis/src/types.ts @@ -19,53 +19,53 @@ export type SharedAxisProps = { axisClassName?: string; /** The class name applied to the axis line element. */ axisLineClassName?: string; - /** If true, will hide the axis line. */ + /** If true, will hide the axis line. */ hideAxisLine?: boolean; - /** If true, will hide the ticks (but not the tick labels). */ + /** If true, will hide the ticks (but not the tick labels). */ hideTicks?: boolean; - /** If true, will hide the '0' value tick and tick label. */ + /** If true, will hide the '0' value tick and tick label. */ hideZero?: boolean; - /** The text for the axis label. */ + /** The text for the axis label. */ label?: string; - /** The class name applied to the axis label text element. */ + /** The class name applied to the axis label text element. */ labelClassName?: string; /** Pixel offset of the axis label (does not include tick label font size, which is accounted for automatically) */ labelOffset?: number; - /** Props applied to the axis label component. */ + /** Props applied to the axis label component. */ labelProps?: Partial; - /** A left pixel offset applied to the entire axis. */ + /** A left pixel offset applied to the entire axis. */ left?: number; /** The number of ticks wanted for the axis (note this is approximate) */ numTicks?: number; - /** Pixel padding to apply to both sides of the axis. */ + /** Pixel padding to apply to both sides of the axis. */ rangePadding?: number; - /** A [d3](https://github.com/d3/d3-scale) or [vx](https://github.com/hshoff/vx/tree/master/packages/vx-scale) scale function. */ + /** A [d3](https://github.com/d3/d3-scale) or [vx](https://github.com/hshoff/vx/tree/master/packages/vx-scale) scale function. */ scale: GenericScale; - /** The color for the stroke of the lines. */ + /** The color for the stroke of the lines. */ stroke?: string; - /** The pixel value for the width of the lines. */ + /** The pixel value for the width of the lines. */ strokeWidth?: number; - /** The pattern of dashes in the stroke. */ + /** The pattern of dashes in the stroke. */ strokeDasharray?: string; - /** The class name applied to each tick group. */ + /** The class name applied to each tick group. */ tickClassName?: string; - /** A [d3 formatter](https://github.com/d3/d3-scale/blob/master/README.md#continuous_tickFormat) for the tick text. */ + /** A [d3 formatter](https://github.com/d3/d3-scale/blob/master/README.md#continuous_tickFormat) for the tick text. */ tickFormat?: TickFormatter; - /** A function that returns props for a given tick label. */ + /** A function that returns props for a given tick label. */ tickLabelProps?: TickLabelProps; - /** The length of the tick lines. */ + /** The length of the tick lines. */ tickLength?: number; - /** The color for the tick's stroke value. */ + /** The color for the tick's stroke value. */ tickStroke?: string; - /** A custom SVG transform value to be applied to each tick group. */ + /** A custom SVG transform value to be applied to each tick group. */ tickTransform?: string; - /** An array of values that determine the number and values of the ticks. Falls back to `scale.ticks()` or `.domain()`. */ + /** An array of values that determine the number and values of the ticks. Falls back to `scale.ticks()` or `.domain()`. */ tickValues?: ScaleInput[]; - /** */ + /** Override the component used to render tick labels (instead of from @vx/text) */ tickComponent?: (tickRendererProps: TickRendererProps) => React.ReactNode; - /** A top pixel offset applied to the entire axis. */ + /** A top pixel offset applied to the entire axis. */ top?: number; - /** For more control over rendering or to add event handlers to datum, pass a function as children. */ + /** For more control over rendering or to add event handlers to datum, pass a function as children. */ children?: (renderProps: ChildRenderProps) => React.ReactNode; }; From 88cc9b33acdea4cba4aef0132df7514566a62eb4 Mon Sep 17 00:00:00 2001 From: Chris Williams Date: Sun, 29 Dec 2019 16:01:49 -0800 Subject: [PATCH 13/13] lint(vx-axis) --- packages/vx-axis/src/axis/Axis.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vx-axis/src/axis/Axis.tsx b/packages/vx-axis/src/axis/Axis.tsx index 40eb0f301d..99248ae8ba 100644 --- a/packages/vx-axis/src/axis/Axis.tsx +++ b/packages/vx-axis/src/axis/Axis.tsx @@ -9,7 +9,7 @@ import getLabelTransform from '../utils/labelTransform'; import ORIENT from '../constants/orientation'; import toString from '../utils/toString'; import toNumberOrUndefined from '../utils/toNumberOrUndefined'; -import { SharedAxisProps, AxisOrientation, TickFormatter } from '../types'; +import { SharedAxisProps, AxisOrientation } from '../types'; export type AxisProps = SharedAxisProps & { orientation?: AxisOrientation;