diff --git a/.changeset/orange-items-cross.md b/.changeset/orange-items-cross.md new file mode 100644 index 000000000..9aceb3dc4 --- /dev/null +++ b/.changeset/orange-items-cross.md @@ -0,0 +1,5 @@ +--- +"victory-selection-container": patch +--- + +Migrated victory-selection-container to TypeScript diff --git a/packages/victory-selection-container/package.json b/packages/victory-selection-container/package.json index 8c1206e1e..6e339830e 100644 --- a/packages/victory-selection-container/package.json +++ b/packages/victory-selection-container/package.json @@ -28,7 +28,8 @@ "react": ">=16.6.0" }, "devDependencies": { - "victory-bar": "^36.8.1" + "victory-bar": "^36.8.1", + "victory-selection-container": "*" }, "publishConfig": { "provenance": true diff --git a/packages/victory-selection-container/src/index.d.ts b/packages/victory-selection-container/src/index.d.ts deleted file mode 100644 index 1c97bee19..000000000 --- a/packages/victory-selection-container/src/index.d.ts +++ /dev/null @@ -1,41 +0,0 @@ -import * as React from "react"; -import { VictoryContainerProps } from "victory-core"; - -interface PointsInterface { - childName?: string | string[]; - eventKey?: string | number; - data?: any; -} - -interface VictorySelectionContainerProps extends VictoryContainerProps { - activateSelectedData?: boolean; - allowSelection?: boolean; - disable?: boolean; - onSelection?: ( - points: PointsInterface[], - bounds: { x: number | Date; y: number | Date }[], - props: VictorySelectionContainerProps, - ) => void; - onSelectionCleared?: (props: VictorySelectionContainerProps) => void; - selectionBlacklist?: string[]; - selectionComponent?: React.ReactElement; - selectionDimension?: "x" | "y"; - selectionStyle?: React.CSSProperties; -} - -export class VictorySelectionContainer extends React.Component< - VictorySelectionContainerProps, - any -> {} - -export const SelectionHelpers: { - getDimension(props: any): any; - getDatasets(props: any): any; - filterDatasets(props: any, datasets: any, bounds: any): any; - getSelectedData(props: any, dataset: any): any; - onMouseDown(evt: any, targetProps: any): any; - onMouseMove(evt: any, targetProps: any): any; - onMouseUp(evt: any, targetProps: any): any; -}; - -export const selectionContainerMixin: (base: Function) => Function; diff --git a/packages/victory-selection-container/src/index.js b/packages/victory-selection-container/src/index.js deleted file mode 100644 index 1cf2803a5..000000000 --- a/packages/victory-selection-container/src/index.js +++ /dev/null @@ -1,5 +0,0 @@ -export { - selectionContainerMixin, - default as VictorySelectionContainer, -} from "./victory-selection-container"; -export { default as SelectionHelpers } from "./selection-helpers"; diff --git a/packages/victory-selection-container/src/index.ts b/packages/victory-selection-container/src/index.ts new file mode 100644 index 000000000..b779c7988 --- /dev/null +++ b/packages/victory-selection-container/src/index.ts @@ -0,0 +1,2 @@ +export * from "./victory-selection-container"; +export * from "./selection-helpers"; diff --git a/packages/victory-selection-container/src/selection-helpers.test.js b/packages/victory-selection-container/src/selection-helpers.test.tsx similarity index 82% rename from packages/victory-selection-container/src/selection-helpers.test.js rename to packages/victory-selection-container/src/selection-helpers.test.tsx index f3a885e4c..a7ce54b73 100644 --- a/packages/victory-selection-container/src/selection-helpers.test.js +++ b/packages/victory-selection-container/src/selection-helpers.test.tsx @@ -1,7 +1,7 @@ import { assign } from "lodash"; import React from "react"; import { VictoryBar } from "victory-bar"; -import SelectionHelpers from "victory-selection-container/lib/selection-helpers"; +import { SelectionHelpers } from "victory-selection-container"; import * as d3Scale from "victory-vendor/d3-scale"; const scale = { x: d3Scale.scaleLinear(), y: d3Scale.scaleLinear() }; @@ -47,12 +47,7 @@ describe("helpers/selection", () => { }, ]; const props = { scale, x1: 0, y1: 0, x2: 0.5, y2: 0.5 }; - const bounds = { x: [0, 1], y: [10, 15] }; - const filteredData = SelectionHelpers.filterDatasets( - props, - datasets, - bounds, - ); + const filteredData = SelectionHelpers.filterDatasets(props, datasets); expect(filteredData).toBeNull(); }); @@ -63,13 +58,8 @@ describe("helpers/selection", () => { ]; const childName = "a"; const datasets = [{ childName, data }]; - const bounds = { x: [0, 1], y: [0, 10] }; const props = { scale, x1: 0, y1: 0, x2: 0.5, y2: 0.5 }; - const filteredData = SelectionHelpers.filterDatasets( - props, - datasets, - bounds, - ); + const filteredData = SelectionHelpers.filterDatasets(props, datasets); const expected = { eventKey: [0], data: [data[0]] }; expect(filteredData).toEqual([assign({ childName }, expected)]); }); diff --git a/packages/victory-selection-container/src/selection-helpers.js b/packages/victory-selection-container/src/selection-helpers.tsx similarity index 89% rename from packages/victory-selection-container/src/selection-helpers.js rename to packages/victory-selection-container/src/selection-helpers.tsx index a3e998381..466c08ceb 100644 --- a/packages/victory-selection-container/src/selection-helpers.js +++ b/packages/victory-selection-container/src/selection-helpers.tsx @@ -1,15 +1,17 @@ -import { Selection, Data, Helpers } from "victory-core"; +import { Selection, Data, Helpers, Datum } from "victory-core"; import { assign, defaults, throttle, isFunction, includes } from "lodash"; import React from "react"; -const SelectionHelpers = { +const ON_MOUSE_MOVE_THROTTLE_MS = 16; + +class SelectionHelpersClass { getDimension(props) { const { horizontal, selectionDimension } = props; if (!horizontal || !selectionDimension) { return selectionDimension; } return selectionDimension === "x" ? "y" : "x"; - }, + } getDatasets(props) { if (props.data) { @@ -38,11 +40,11 @@ const SelectionHelpers = { iteratee, props, ); - }, + } - filterDatasets(props, datasets, bounds) { + filterDatasets(props, datasets) { const filtered = datasets.reduce((memo, dataset) => { - const selectedData = this.getSelectedData(props, dataset.data, bounds); + const selectedData = this.getSelectedData(props, dataset.data); memo = selectedData ? memo.concat({ childName: dataset.childName, @@ -53,7 +55,7 @@ const SelectionHelpers = { return memo; }, []); return filtered.length ? filtered : null; - }, + } getSelectedData(props, dataset) { const { x1, y1, x2, y2 } = props; @@ -66,8 +68,8 @@ const SelectionHelpers = { scaledPoint.y <= Math.max(y1, y2) ); }; - const eventKey = []; - const data = []; + const eventKey: number[] = []; + const data: Datum[] = []; let count = 0; for (let index = 0, len = dataset.length; index < len; index++) { const datum = dataset[index]; @@ -78,10 +80,9 @@ const SelectionHelpers = { } } return count > 0 ? { eventKey, data } : null; - }, + } - // eslint-disable-next-line complexity, max-statements - onMouseDown(evt, targetProps) { + onMouseDown = (evt, targetProps) => { evt.preventDefault(); const { activateSelectedData, allowSelection, polar, selectedData } = targetProps; @@ -126,9 +127,9 @@ const SelectionHelpers = { : []; return parentMutation.concat(...dataMutation); - }, + }; - onMouseMove(evt, targetProps) { + private handleMouseMove = (evt, targetProps) => { const { allowSelection, select, polar } = targetProps; const dimension = this.getDimension(targetProps); if (!allowSelection || !select) { @@ -150,9 +151,14 @@ const SelectionHelpers = { return { x2, y2, parentSVG }; }, }; - }, + }; + + onMouseMove = throttle(this.handleMouseMove, ON_MOUSE_MOVE_THROTTLE_MS, { + leading: true, + trailing: false, + }); - onMouseUp(evt, targetProps) { + onMouseUp = (evt, targetProps) => { const { activateSelectedData, allowSelection, x2, y2 } = targetProps; if (!allowSelection) { return null; @@ -169,7 +175,7 @@ const SelectionHelpers = { } const datasets = this.getDatasets(targetProps); const bounds = Selection.getBounds(targetProps); - const selectedData = this.filterDatasets(targetProps, datasets, bounds); + const selectedData = this.filterDatasets(targetProps, datasets); const mutatedProps = { selectedData, datasets, @@ -209,16 +215,7 @@ const SelectionHelpers = { : []; return parentMutation.concat(dataMutation); - }, -}; - -export default { - ...SelectionHelpers, - onMouseDown: SelectionHelpers.onMouseDown.bind(SelectionHelpers), - onMouseUp: SelectionHelpers.onMouseUp.bind(SelectionHelpers), - onMouseMove: throttle( - SelectionHelpers.onMouseMove.bind(SelectionHelpers), - 16, // eslint-disable-line no-magic-numbers - { leading: true, trailing: false }, - ), -}; + }; +} + +export const SelectionHelpers = new SelectionHelpersClass(); diff --git a/packages/victory-selection-container/src/victory-selection-container.js b/packages/victory-selection-container/src/victory-selection-container.tsx similarity index 60% rename from packages/victory-selection-container/src/victory-selection-container.js rename to packages/victory-selection-container/src/victory-selection-container.tsx index 0f3f6b35e..5fcb322a4 100644 --- a/packages/victory-selection-container/src/victory-selection-container.js +++ b/packages/victory-selection-container/src/victory-selection-container.tsx @@ -1,23 +1,45 @@ -import PropTypes from "prop-types"; import React from "react"; -import { VictoryContainer, Rect } from "victory-core"; -import SelectionHelpers from "./selection-helpers"; +import { + Datum, + Rect, + VictoryContainer, + VictoryContainerProps, +} from "victory-core"; +import { SelectionHelpers } from "./selection-helpers"; -export const selectionContainerMixin = (base) => - class VictorySelectionContainer extends base { +export interface VictorySelectionContainerProps extends VictoryContainerProps { + activateSelectedData?: boolean; + allowSelection?: boolean; + disable?: boolean; + onSelection?: ( + points: { + childName?: string | string[]; + eventKey?: string | number; + data?: Datum[]; + }[], + bounds: { + x: number | Date; + y: number | Date; + }[], + props: VictorySelectionContainerProps, + ) => void; + horizontal?: boolean; + onSelectionCleared?: (props: VictorySelectionContainerProps) => void; + selectionBlacklist?: string[]; + selectionComponent?: React.ReactElement; + selectionDimension?: "x" | "y"; + selectionStyle?: React.CSSProperties; +} + +type ComponentClass = { new (props: TProps): React.Component }; + +export function selectionContainerMixin< + TBase extends ComponentClass, + TProps extends VictorySelectionContainerProps, +>(Base: TBase) { + // @ts-expect-error "TS2545: A mixin class must have a constructor with a single rest parameter of type 'any[]'." + return class VictorySelectionContainer extends Base { static displayName = "VictorySelectionContainer"; - static propTypes = { - ...VictoryContainer.propTypes, - activateSelectedData: PropTypes.bool, - allowSelection: PropTypes.bool, - disable: PropTypes.bool, - onSelection: PropTypes.func, - onSelectionCleared: PropTypes.func, - selectionBlacklist: PropTypes.arrayOf(PropTypes.string), - selectionComponent: PropTypes.element, - selectionDimension: PropTypes.oneOf(["x", "y"]), - selectionStyle: PropTypes.object, - }; static defaultProps = { ...VictoryContainer.defaultProps, activateSelectedData: true, @@ -30,7 +52,7 @@ export const selectionContainerMixin = (base) => }, }; - static defaultEvents = (props) => { + static defaultEvents = (props: TProps) => { return [ { target: "parent", @@ -90,12 +112,12 @@ export const selectionContainerMixin = (base) => } // Overrides method in VictoryContainer - getChildren(props) { + getChildren(props: TProps) { return [...React.Children.toArray(props.children), this.getRect(props)]; } }; +} -export default selectionContainerMixin(VictoryContainer); -// @ts-expect-error IMPORTANT: when converting this file to TypeScript, you must export the type as well: -// export const VictorySelectionContainer = selectionContainerMixin(VictoryContainer); -// export type VictorySelectionContainer = typeof VictorySelectionContainer; +export const VictorySelectionContainer = + selectionContainerMixin(VictoryContainer); +export type VictorySelectionContainer = typeof VictorySelectionContainer; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c6e67ab54..2426bbec0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -634,12 +634,14 @@ importers: prop-types: ^15.8.1 victory-bar: ^36.8.1 victory-core: ^36.8.1 + victory-selection-container: '*' dependencies: lodash: 4.17.21 prop-types: 15.8.1 victory-core: link:../victory-core devDependencies: victory-bar: link:../victory-bar + victory-selection-container: 'link:' packages/victory-shared-events: specifiers: