Skip to content

Commit

Permalink
Migrate victory-tooltip to typescript (#2725)
Browse files Browse the repository at this point in the history
  • Loading branch information
carbonrobot authored Jan 19, 2024
1 parent e42ba31 commit 3cd3cea
Show file tree
Hide file tree
Showing 13 changed files with 265 additions and 262 deletions.
6 changes: 6 additions & 0 deletions .changeset/tender-bees-talk.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"victory-core": patch
"victory-tooltip": patch
---

Migrate victory-tooltip to typescript
1 change: 1 addition & 0 deletions packages/victory-core/src/exports.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,7 @@ describe("victory-core", () => {
"getTransitionPropsFactory": [Function],
},
"UserProps": Object {
"assert": [Function],
"getSafeUserProps": [Function],
"withSafeUserProps": [Function],
},
Expand Down
13 changes: 8 additions & 5 deletions packages/victory-core/src/types/callbacks.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { D3Scale, Datum, ID } from "./prop-types";
import { D3Scale, Datum, ID, ScalePropType } from "./prop-types";
import { BlockProps, OrientationTypes } from "../victory-theme/types";

/**
Expand All @@ -16,10 +16,13 @@ export interface CallbackArgs {
index?: ID;
x?: number;
y?: number;
scale?: {
x?: D3Scale;
y?: D3Scale;
};
scale?:
| ScalePropType
| D3Scale
| {
x?: ScalePropType | D3Scale;
y?: ScalePropType | D3Scale;
};
tick?: any;
ticks?: any;
text?: any;
Expand Down
14 changes: 14 additions & 0 deletions packages/victory-core/src/victory-util/user-props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,20 @@ const testIfSafeProp = (key: string): key is SafeAttribute => {
return false;
};

/**
* Asserts that value is not null or undefined, throwing an error if it is.
* @param value The value to assert
* @param message The error message to throw
*/
export function assert<T>(
value: T,
message?: string,
): asserts value is NonNullable<T> {
if (value === undefined || value === null) {
throw new Error(message);
}
}

/**
* getSafeUserProps - function that takes in a props object and removes any
* key-value entries that do not match filter strings in the USER_PROPS_SAFELIST
Expand Down
3 changes: 3 additions & 0 deletions packages/victory-tooltip/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
"prop-types": "^15.8.1",
"victory-core": "^36.8.2"
},
"devDependencies": {
"victory-tooltip": "*"
},
"peerDependencies": {
"react": ">=16.6.0"
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import React from "react";
import { Flyout } from "victory-tooltip";
import { render } from "@testing-library/react";
import { Flyout } from "victory-tooltip";

import { SVGWrapper } from "../../../test/helpers";

describe("victory-primitives/flyout", () => {
const baseProps = {
Expand All @@ -17,7 +19,7 @@ describe("victory-primitives/flyout", () => {
describe("rendering", () => {
it("renders a flyout path", () => {
const { container } = render(<Flyout {...baseProps} />, {
wrapper: "svg",
wrapper: SVGWrapper,
});
const path = container.querySelector("path");

Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,67 @@
/* eslint no-magic-numbers: ["error", { "ignore": [-1, 0, 1, 2] }]*/
import React from "react";
import PropTypes from "prop-types";
import { Helpers, CommonProps, Path, UserProps } from "victory-core";
import { isPlainObject, assign } from "lodash";
import {
Helpers,
Path,
UserProps,
VictoryCommonProps,
OrientationTypes,
VictoryStyleObject,
StringOrNumberOrCallback,
} from "victory-core";

const getVerticalPath = (props) => {
export interface FlyoutProps extends VictoryCommonProps {
active?: boolean;
center?: {
x: number;
y: number;
};
className?: string;
clipPath?: string;
cornerRadius?: number;
data?: any[];
datum?: object;
dx?: number;
dy?: number;
events?: object;
id?: StringOrNumberOrCallback;
index?: number;
orientation?: OrientationTypes;
pathComponent?: React.ReactElement;
pointerLength?: number;
pointerWidth?: number;
role?: string;
shapeRendering?: string;
style?: VictoryStyleObject;
transform?: string;
x?: number;
y?: number;
}

interface FlyoutPathProps {
center: {
x: number;
y: number;
};
cornerRadius: number;
dx?: number;
dy?: number;
height: number;
orientation: OrientationTypes;
pointerLength: number;
pointerWidth: number;
width: number;
x: number;
y: number;
}

const getVerticalPath = (props: FlyoutPathProps) => {
const { pointerWidth, cornerRadius, orientation, width, height, center } =
props;
const sign = orientation === "bottom" ? 1 : -1;
const x = props.x + (props.dx || 0);
const y = props.y + (props.dy || 0);
const centerX = isPlainObject(center) && center.x;
const centerY = isPlainObject(center) && center.y;
const centerX = center.x;
const centerY = center.y;
const pointerEdge = centerY + sign * (height / 2);
const oppositeEdge = centerY - sign * (height / 2);
const rightEdge = centerX + width / 2;
Expand All @@ -35,14 +85,14 @@ const getVerticalPath = (props) => {
z`;
};

const getHorizontalPath = (props) => {
const getHorizontalPath = (props: FlyoutPathProps) => {
const { pointerWidth, cornerRadius, orientation, width, height, center } =
props;
const sign = orientation === "left" ? 1 : -1;
const x = props.x + (props.dx || 0);
const y = props.y + (props.dy || 0);
const centerX = isPlainObject(center) && center.x;
const centerY = isPlainObject(center) && center.y;
const centerX = center.x;
const centerY = center.y;
const pointerEdge = centerX - sign * (width / 2);
const oppositeEdge = centerX + sign * (width / 2);
const bottomEdge = centerY + height / 2;
Expand All @@ -66,14 +116,14 @@ const getHorizontalPath = (props) => {
z`;
};

const getFlyoutPath = (props) => {
const getFlyoutPath = (props: FlyoutPathProps) => {
const orientation = props.orientation || "top";
return orientation === "left" || orientation === "right"
? getHorizontalPath(props)
: getVerticalPath(props);
};

const evaluateProps = (props) => {
const evaluateProps = (props: FlyoutProps) => {
/**
* Potential evaluated props are:
* `id`
Expand All @@ -82,7 +132,7 @@ const evaluateProps = (props) => {
const id = Helpers.evaluateProp(props.id, props);
const style = Helpers.evaluateStyle(props.style, props);

return assign({}, props, { id, style });
return { ...props, id, style };
};

const defaultProps = {
Expand All @@ -91,38 +141,40 @@ const defaultProps = {
shapeRendering: "auto",
};

const Flyout = (initialProps) => {
export const Flyout: React.FC<FlyoutProps> = (initialProps) => {
const props = evaluateProps({ ...defaultProps, ...initialProps });
const userProps = UserProps.getSafeUserProps(props);

return React.cloneElement(props.pathComponent, {
// check for required props for this subcomponent
// they should be passed in from the wrapper
UserProps.assert(props.height, "Flyout props[height] is undefined");
UserProps.assert(props.width, "Flyout props[width] is undefined");
UserProps.assert(props.x, "Flyout props[x] is undefined");
UserProps.assert(props.y, "Flyout props[y] is undefined");

const flyoutPathProps: FlyoutPathProps = {
center: props.center || { x: 0, y: 0 },
cornerRadius: props.cornerRadius || 0,
dx: props.dx,
dy: props.dy,
height: props.height,
orientation: props.orientation || "top",
pointerLength: props.pointerLength || 0,
pointerWidth: props.pointerWidth || 0,
width: props.width,
x: props.x,
y: props.y,
};

return React.cloneElement(props.pathComponent!, {
...props.events,
...userProps,
style: props.style,
d: getFlyoutPath(props),
d: getFlyoutPath(flyoutPathProps),
className: props.className,
shapeRendering: props.shapeRendering,
role: props.role,
transform: props.transform,
clipPath: props.clipPath,
});
};

Flyout.propTypes = {
...CommonProps.primitiveProps,
center: PropTypes.shape({ x: PropTypes.number, y: PropTypes.number }),
cornerRadius: PropTypes.number,
datum: PropTypes.object,
dx: PropTypes.number,
dy: PropTypes.number,
height: PropTypes.number,
orientation: PropTypes.oneOf(["top", "bottom", "left", "right"]),
pathComponent: PropTypes.element,
pointerLength: PropTypes.number,
pointerWidth: PropTypes.number,
width: PropTypes.number,
x: PropTypes.number,
y: PropTypes.number,
};

export default Flyout;
92 changes: 0 additions & 92 deletions packages/victory-tooltip/src/index.d.ts

This file was deleted.

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

This file was deleted.

2 changes: 2 additions & 0 deletions packages/victory-tooltip/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./victory-tooltip";
export * from "./flyout";
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import React from "react";
import { Flyout, VictoryTooltip } from "victory-tooltip";
import { VictoryContainer, VictoryLabel } from "victory-core";
import { fireEvent, screen, render } from "@testing-library/react";
import { VictoryContainer, VictoryLabel } from "victory-core";
import { Flyout, VictoryTooltip } from "victory-tooltip";

describe("components/victory-tooltip", () => {
const flyoutId = "flyout-1";
const labelId = "label-1";

/** @type {VictoryTooltipProps} */
const baseProps = {
x: 0,
y: 0,
Expand Down
Loading

1 comment on commit 3cd3cea

@vercel
Copy link

@vercel vercel bot commented on 3cd3cea Jan 19, 2024

Choose a reason for hiding this comment

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

Please sign in to comment.