Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate victory-voronoi to TypeScript #2726

Merged
merged 1 commit into from
Jan 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/long-files-itch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"victory-voronoi": patch
---

Migrate victory-voronoi to TypeScript
46 changes: 0 additions & 46 deletions packages/victory-voronoi/src/index.d.ts

This file was deleted.

2 changes: 0 additions & 2 deletions packages/victory-voronoi/src/index.js

This file was deleted.

2 changes: 2 additions & 0 deletions packages/victory-voronoi/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./victory-voronoi";
export * from "./voronoi";
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from "react";
import { random, range } from "lodash";
import { calculateD3Path } from "../../../test/helpers";
import { VictoryVoronoi, Voronoi } from "victory-voronoi";
import { VictoryVoronoi, VictoryVoronoiProps, Voronoi } from "victory-voronoi";
import { fireEvent, render, screen } from "@testing-library/react";

describe("components/victory-voronoi", () => {
Expand All @@ -19,8 +19,8 @@ describe("components/victory-voronoi", () => {
it("renders an svg with the correct width and height", () => {
const { container } = render(<VictoryVoronoi />);
const svg = container.querySelector("svg");
expect(svg.style.width).toEqual("100%");
expect(svg.style.height).toEqual("100%");
expect(svg?.style.width).toEqual("100%");
expect(svg?.style.height).toEqual("100%");
});

it("renders an svg with the correct viewbox", () => {
Expand All @@ -33,7 +33,7 @@ describe("components/victory-voronoi", () => {

describe("component rendering with data", () => {
it("renders the correct d3 path", () => {
const props = {
const props: VictoryVoronoiProps = {
width: 400,
height: 300,
padding: 50,
Expand Down Expand Up @@ -68,7 +68,7 @@ describe("components/victory-voronoi", () => {

const renderedDataProps = screen
.getAllByTestId("voronoi-1")
.map((node) => JSON.parse(node.getAttribute("data-props-json")));
.map((node) => JSON.parse(node.getAttribute("data-props-json") || ""));
expect(renderedDataProps.map((props) => props.datum._x)).toEqual([
0, 1, 2, 3, 4,
]);
Expand All @@ -91,7 +91,7 @@ describe("components/victory-voronoi", () => {

const renderedDataProps = screen
.getAllByTestId("voronoi-1")
.map((node) => JSON.parse(node.getAttribute("data-props-json")));
.map((node) => JSON.parse(node.getAttribute("data-props-json") || ""));

expect(renderedDataProps.map((props) => props.datum._x)).toEqual([
4, 3, 2, 1, 0,
Expand Down Expand Up @@ -125,7 +125,7 @@ describe("components/victory-voronoi", () => {
/>,
);
const svg = container.querySelector("svg");
fireEvent.click(svg);
fireEvent.click(svg!);
expect(clickHandler).toBeCalled();
// the first argument is the standard evt object
expect(Object.keys(clickHandler.mock.calls[0][1])).toEqual(
Expand Down Expand Up @@ -164,7 +164,7 @@ describe("components/victory-voronoi", () => {
const clickHandler = jest.fn();
const { container } = render(
<VictoryVoronoi
label="okay"
labels={["okay"]}
events={[
{
target: "labels",
Expand All @@ -176,8 +176,7 @@ describe("components/victory-voronoi", () => {

const labels = container.querySelectorAll("text");

// TODO: figure out why there's no labels rendering?
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The label prop should have been labels

expect(labels).toHaveLength(0);
expect(labels).toHaveLength(1);

labels.forEach((node, index) => {
clickHandler.mockClear();
Expand Down Expand Up @@ -211,7 +210,7 @@ describe("components/victory-voronoi", () => {
dataComponent={
<Voronoi
ariaLabel={({ datum }) => `${datum.x}`}
tabIndex={({ index }) => index + 6}
tabIndex={({ index }) => Number(index) + 6}
/>
}
/>,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React from "react";
import {
PropTypes as CustomPropTypes,
Helpers,
VictoryLabel,
addEvents,
Expand All @@ -9,20 +8,46 @@ import {
DefaultTransitions,
Data,
Domain,
CommonProps,
UserProps,
EventPropTypeInterface,
EventsMixinClass,
VictoryCommonProps,
VictoryDatableProps,
VictoryLabelableProps,
VictoryMultiLabelableProps,
VictoryStyleInterface,
} from "victory-core";
import Voronoi from "./voronoi";
import { Voronoi } from "./voronoi";
import { getBaseProps } from "./helper-methods";

export type VictoryVoronoiSortOrderType = "ascending" | "descending";

export interface VictoryVoronoiProps
extends Omit<VictoryCommonProps, "polar">,
VictoryDatableProps,
VictoryLabelableProps,
VictoryMultiLabelableProps {
events?: EventPropTypeInterface<
string,
string | number | (string | number)[]
>[];
type?: number;
sortOrder?: VictoryVoronoiSortOrderType;
size?: number | { (data: any): number };
style?: VictoryStyleInterface;
}

const fallbackProps = {
width: 450,
height: 300,
padding: 50,
};

class VictoryVoronoi extends React.Component {
static animationWhitelist = [
// eslint-disable-next-line @typescript-eslint/no-empty-interface
interface VictoryVoronoiBase extends EventsMixinClass<VictoryVoronoiProps> {}

class VictoryVoronoiBase extends React.Component<VictoryVoronoiProps> {
static animationWhitelist: (keyof VictoryVoronoiProps)[] = [
"data",
"domain",
"height",
Expand All @@ -37,13 +62,7 @@ class VictoryVoronoi extends React.Component {
static role = "voronoi";
static defaultTransitions = DefaultTransitions.discreteTransitions();

static propTypes = {
...CommonProps.baseProps,
...CommonProps.dataProps,
size: CustomPropTypes.nonNegative,
};

static defaultProps = {
static defaultProps: VictoryVoronoiProps = {
containerComponent: <VictoryContainer />,
dataComponent: <Voronoi />,
labelComponent: <VictoryLabel />,
Expand All @@ -56,8 +75,9 @@ class VictoryVoronoi extends React.Component {

static getDomain = Domain.getDomain;
static getData = Data.getData;
static getBaseProps = (props) => getBaseProps(props, fallbackProps);
static expectedComponents = [
static getBaseProps = (props: VictoryVoronoiProps) =>
getBaseProps(props, fallbackProps);
static expectedComponents: (keyof VictoryVoronoiProps)[] = [
"dataComponent",
"labelComponent",
"groupComponent",
Expand All @@ -69,7 +89,7 @@ class VictoryVoronoi extends React.Component {
return !!this.props.animate;
}

render() {
render(): React.ReactElement {
const { animationWhitelist, role } = VictoryVoronoi;
const props = Helpers.modifyProps(this.props, fallbackProps, role);

Expand All @@ -87,4 +107,4 @@ class VictoryVoronoi extends React.Component {
}
}

export default addEvents(VictoryVoronoi);
export const VictoryVoronoi = addEvents(VictoryVoronoiBase);
Original file line number Diff line number Diff line change
@@ -1,24 +1,35 @@
/* eslint no-magic-numbers: ["error", { "ignore": [2] }]*/
import React from "react";
import PropTypes from "prop-types";
import { assign } from "lodash";
import {
Helpers,
CommonProps,
ClipPath,
Path,
Circle,
UserProps,
VictoryCommonPrimitiveProps,
} from "victory-core";

const getVoronoiPath = (props) => {
export interface VoronoiProps extends VictoryCommonPrimitiveProps {
circleComponent?: React.ReactElement;
clipId?: number | string;
clipPathComponent?: React.ReactElement;
datum?: any;
groupComponent?: React.ReactElement;
pathComponent?: React.ReactElement;
polygon?: [];
size?: number;
x?: number;
y?: number;
}

const getVoronoiPath = (props: VoronoiProps) => {
const { polygon } = props;
return Array.isArray(polygon) && polygon.length
? `M ${props.polygon.join("L")} Z`
? `M ${props.polygon?.join("L")} Z`
: "";
};

const evaluateProps = (props) => {
function evaluateProps<T extends VoronoiProps>(props: T) {
/**
* Potential evaluated props are:
* `aria-label`
Expand All @@ -33,7 +44,7 @@ const evaluateProps = (props) => {
const style = Helpers.evaluateStyle(props.style, props);
const tabIndex = Helpers.evaluateProp(props.tabIndex, props);
return assign({}, props, { ariaLabel, id, size, style, tabIndex });
};
}

const defaultProps = {
pathComponent: <Path />,
Expand All @@ -44,9 +55,8 @@ const defaultProps = {
shapeRendering: "auto",
};

const Voronoi = (initialProps) => {
export const Voronoi = (initialProps: VoronoiProps) => {
const props = evaluateProps({ ...defaultProps, ...initialProps });

const {
ariaLabel,
role,
Expand All @@ -58,6 +68,7 @@ const Voronoi = (initialProps) => {
size,
tabIndex,
} = props;

const voronoiPath = getVoronoiPath(props);
const sharedProps = {
"aria-label": ariaLabel,
Expand Down Expand Up @@ -99,19 +110,3 @@ const Voronoi = (initialProps) => {
d: voronoiPath,
});
};

Voronoi.propTypes = {
...CommonProps.primitiveProps,
circleComponent: PropTypes.element,
clipId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
clipPathComponent: PropTypes.element,
datum: PropTypes.object,
groupComponent: PropTypes.element,
pathComponent: PropTypes.element,
polygon: PropTypes.array,
size: PropTypes.number,
x: PropTypes.number,
y: PropTypes.number,
};

export default Voronoi;