victory-cursor-container 37.0.2 → 37.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
+ /* eslint-disable complexity */
1
2
  import React from "react";
2
3
  import {
3
- VictoryContainer,
4
4
  Helpers,
5
5
  VictoryContainerProps,
6
6
  CoordinatesPropType,
@@ -8,6 +8,10 @@ import {
8
8
  ValueOrAccessor,
9
9
  VictoryLabel,
10
10
  LineSegment,
11
+ VictoryContainer,
12
+ VictoryEventHandler,
13
+ DomainTuple,
14
+ PaddingProps,
11
15
  } from "victory-core";
12
16
  import { defaults, isObject } from "lodash";
13
17
  import { CursorHelpers } from "./cursor-helpers";
@@ -22,191 +26,208 @@ export interface VictoryCursorContainerProps extends VictoryContainerProps {
22
26
  cursorLabelOffset?: CursorCoordinatesPropType;
23
27
  defaultCursorValue?: CursorCoordinatesPropType;
24
28
  disable?: boolean;
29
+ horizontal?: boolean;
30
+ padding?: PaddingProps;
25
31
  onCursorChange?: (
26
32
  value: CursorCoordinatesPropType,
27
33
  props: VictoryCursorContainerProps,
28
34
  ) => void;
29
35
  }
30
36
 
31
- type ComponentClass<TProps> = { new (props: TProps): React.Component<TProps> };
32
-
33
- export function cursorContainerMixin<
34
- TBase extends ComponentClass<TProps>,
35
- TProps extends VictoryCursorContainerProps,
36
- >(Base: TBase) {
37
- // @ts-expect-error "TS2545: A mixin class must have a constructor with a single rest parameter of type 'any[]'."
38
- return class VictoryCursorContainer extends Base {
39
- static displayName = "VictoryCursorContainer";
40
- static defaultProps = {
41
- ...VictoryContainer.defaultProps,
42
- cursorLabelComponent: <VictoryLabel />,
43
- cursorLabelOffset: {
44
- x: 5,
45
- y: -10,
46
- },
47
- cursorComponent: <LineSegment />,
48
- };
49
- static defaultEvents(props) {
50
- return [
51
- {
52
- target: "parent",
53
- eventHandlers: {
54
- onMouseLeave: (evt, targetProps) => {
55
- return props.disable
56
- ? {}
57
- : CursorHelpers.onMouseLeave(evt, targetProps);
58
- },
59
- onTouchCancel: () => {
60
- return [];
61
- },
62
- onMouseMove: (evt, targetProps) => {
63
- return props.disable
64
- ? {}
65
- : CursorHelpers.onMouseMove(evt, targetProps);
66
- },
67
- onTouchMove: (evt, targetProps) => {
68
- return props.disable
69
- ? {}
70
- : CursorHelpers.onMouseMove(evt, targetProps);
71
- },
72
- },
73
- },
74
- ];
75
- }
37
+ interface VictoryCursorContainerMutatedProps
38
+ extends VictoryCursorContainerProps {
39
+ cursorValue: CoordinatesPropType | null;
40
+ domain: { x: DomainTuple; y: DomainTuple };
41
+ }
76
42
 
77
- getCursorPosition(props) {
78
- const { cursorValue, defaultCursorValue, domain, cursorDimension } =
79
- props;
80
- if (cursorValue) {
81
- return cursorValue;
82
- }
43
+ export const VICTORY_CURSOR_CONTAINER_DEFAULT_PROPS = {
44
+ cursorLabelComponent: <VictoryLabel />,
45
+ cursorLabelOffset: {
46
+ x: 5,
47
+ y: -10,
48
+ },
49
+ cursorComponent: <LineSegment />,
50
+ };
51
+
52
+ export const useVictoryCursorContainer = (
53
+ initialProps: VictoryCursorContainerProps,
54
+ ) => {
55
+ const props = {
56
+ ...VICTORY_CURSOR_CONTAINER_DEFAULT_PROPS,
57
+ ...(initialProps as VictoryCursorContainerMutatedProps),
58
+ };
59
+ const { children } = props;
83
60
 
84
- if (typeof defaultCursorValue === "number") {
85
- return {
86
- x: (domain.x[0] + domain.x[1]) / 2,
87
- y: (domain.y[0] + domain.y[1]) / 2,
88
- [cursorDimension]: defaultCursorValue,
89
- };
90
- }
61
+ const getCursorPosition = () => {
62
+ const { cursorValue, defaultCursorValue, domain, cursorDimension } = props;
63
+ if (cursorValue) {
64
+ return cursorValue;
65
+ }
91
66
 
92
- return defaultCursorValue;
67
+ if (typeof defaultCursorValue === "number") {
68
+ return {
69
+ x: ((domain.x[0] as number) + (domain.x[1] as number)) / 2,
70
+ y: ((domain.y[0] as number) + (domain.y[1] as number)) / 2,
71
+ ...(cursorDimension ? { [cursorDimension]: defaultCursorValue } : {}),
72
+ };
93
73
  }
94
74
 
95
- getCursorLabelOffset(props) {
96
- const { cursorLabelOffset } = props;
75
+ return defaultCursorValue;
76
+ };
97
77
 
98
- if (typeof cursorLabelOffset === "number") {
99
- return {
100
- x: cursorLabelOffset,
101
- y: cursorLabelOffset,
102
- };
103
- }
78
+ const getCursorLabelOffset = () => {
79
+ const { cursorLabelOffset } = props;
104
80
 
105
- return cursorLabelOffset;
81
+ if (typeof cursorLabelOffset === "number") {
82
+ return {
83
+ x: cursorLabelOffset,
84
+ y: cursorLabelOffset,
85
+ };
106
86
  }
107
87
 
108
- getPadding(props) {
109
- if (props.padding === undefined) {
110
- const child = props.children.find((c) => {
111
- return isObject(c.props) && c.props.padding !== undefined;
112
- });
113
- return Helpers.getPadding(child.props);
114
- }
115
- return Helpers.getPadding(props);
116
- }
88
+ return cursorLabelOffset;
89
+ };
117
90
 
118
- getCursorElements(props) {
119
- // eslint-disable-line max-statements
120
- const {
121
- scale,
122
- cursorLabelComponent,
123
- cursorLabel,
124
- cursorComponent,
125
- width,
126
- height,
127
- name,
128
- horizontal,
129
- theme,
130
- } = props;
131
- const cursorDimension = CursorHelpers.getDimension(props);
132
- const cursorValue = this.getCursorPosition(props);
133
- const cursorLabelOffset = this.getCursorLabelOffset(props);
134
-
135
- if (!cursorValue) {
136
- return [];
137
- }
91
+ const getPadding = () => {
92
+ if (props.padding === undefined) {
93
+ const child = Array.isArray(props.children)
94
+ ? props.children.find((c: any) => {
95
+ return isObject(c.props) && c.props.padding !== undefined;
96
+ })
97
+ : props.children;
98
+ return Helpers.getPadding(child?.props);
99
+ }
100
+ return Helpers.getPadding(props);
101
+ };
138
102
 
139
- const newElements: React.ReactElement[] = [];
140
- const padding = this.getPadding(props);
141
- const cursorCoordinates = {
142
- x: horizontal ? scale.y(cursorValue.y) : scale.x(cursorValue.x),
143
- y: horizontal ? scale.x(cursorValue.x) : scale.y(cursorValue.y),
144
- };
145
- if (cursorLabel) {
146
- let labelProps = defaults(
147
- { active: true },
148
- cursorLabelComponent.props,
149
- {
150
- x: cursorCoordinates.x + cursorLabelOffset.x,
151
- y: cursorCoordinates.y + cursorLabelOffset.y,
152
- datum: cursorValue,
153
- active: true,
154
- key: `${name}-cursor-label`,
155
- },
156
- );
157
- if (Helpers.isTooltip(cursorLabelComponent)) {
158
- const tooltipTheme = (theme && theme.tooltip) || {};
159
- labelProps = defaults({}, labelProps, tooltipTheme);
160
- }
161
- newElements.push(
162
- React.cloneElement(
163
- cursorLabelComponent,
164
- defaults({}, labelProps, {
165
- text: Helpers.evaluateProp(cursorLabel, labelProps),
166
- }),
167
- ),
168
- );
169
- }
103
+ const getCursorElements = () => {
104
+ // eslint-disable-line max-statements
105
+ const {
106
+ scale,
107
+ cursorLabelComponent,
108
+ cursorLabel,
109
+ cursorComponent,
110
+ width,
111
+ height,
112
+ name,
113
+ horizontal,
114
+ theme,
115
+ } = props;
116
+ const cursorDimension = CursorHelpers.getDimension(props);
117
+ const cursorValue = getCursorPosition();
118
+ const cursorLabelOffset = getCursorLabelOffset();
119
+
120
+ if (!cursorValue) {
121
+ return [];
122
+ }
170
123
 
171
- const cursorStyle = Object.assign(
172
- { stroke: "black" },
173
- cursorComponent.props.style,
174
- );
175
- if (cursorDimension === "x" || cursorDimension === undefined) {
176
- newElements.push(
177
- React.cloneElement(cursorComponent, {
178
- key: `${name}-x-cursor`,
179
- x1: cursorCoordinates.x,
180
- x2: cursorCoordinates.x,
181
- y1: padding.top,
182
- y2: height - padding.bottom,
183
- style: cursorStyle,
184
- }),
185
- );
124
+ const newElements: React.ReactElement[] = [];
125
+ const padding = getPadding();
126
+ const cursorCoordinates =
127
+ scale &&
128
+ "x" in scale &&
129
+ "y" in scale &&
130
+ typeof scale.y === "function" &&
131
+ typeof scale.x === "function"
132
+ ? {
133
+ x: horizontal ? scale.y(cursorValue.y) : scale.x(cursorValue.x),
134
+ y: horizontal ? scale.x(cursorValue.x) : scale.y(cursorValue.y),
135
+ }
136
+ : {
137
+ x: cursorValue.x,
138
+ y: cursorValue.y,
139
+ };
140
+ if (cursorLabel) {
141
+ let labelProps = defaults({ active: true }, cursorLabelComponent.props, {
142
+ x: cursorCoordinates.x + cursorLabelOffset.x,
143
+ y: cursorCoordinates.y + cursorLabelOffset.y,
144
+ datum: cursorValue,
145
+ active: true,
146
+ key: `${name}-cursor-label`,
147
+ });
148
+ if (Helpers.isTooltip(cursorLabelComponent)) {
149
+ const tooltipTheme = (theme && theme.tooltip) || {};
150
+ labelProps = defaults({}, labelProps, tooltipTheme);
186
151
  }
187
- if (cursorDimension === "y" || cursorDimension === undefined) {
188
- newElements.push(
189
- React.cloneElement(cursorComponent, {
190
- key: `${name}-y-cursor`,
191
- x1: padding.left,
192
- x2: width - padding.right,
193
- y1: cursorCoordinates.y,
194
- y2: cursorCoordinates.y,
195
- style: cursorStyle,
152
+ newElements.push(
153
+ React.cloneElement(
154
+ cursorLabelComponent,
155
+ defaults({}, labelProps, {
156
+ text: Helpers.evaluateProp(cursorLabel, labelProps),
196
157
  }),
197
- );
198
- }
199
- return newElements;
158
+ ),
159
+ );
200
160
  }
201
161
 
202
- // Overrides method in VictoryContainer
203
- getChildren(props) {
204
- return [
205
- ...React.Children.toArray(props.children),
206
- ...this.getCursorElements(props),
207
- ];
162
+ const cursorStyle = Object.assign(
163
+ { stroke: "black" },
164
+ cursorComponent.props.style,
165
+ );
166
+ if (cursorDimension === "x" || cursorDimension === undefined) {
167
+ newElements.push(
168
+ React.cloneElement(cursorComponent, {
169
+ key: `${name}-x-cursor`,
170
+ x1: cursorCoordinates.x,
171
+ x2: cursorCoordinates.x,
172
+ y1: padding.top,
173
+ y2: (typeof height === "number" ? height : 0) - padding.bottom,
174
+ style: cursorStyle,
175
+ }),
176
+ );
177
+ }
178
+ if (cursorDimension === "y" || cursorDimension === undefined) {
179
+ newElements.push(
180
+ React.cloneElement(cursorComponent, {
181
+ key: `${name}-y-cursor`,
182
+ x1: padding.left,
183
+ x2: (typeof width === "number" ? width : 0) - padding.right,
184
+ y1: cursorCoordinates.y,
185
+ y2: cursorCoordinates.y,
186
+ style: cursorStyle,
187
+ }),
188
+ );
208
189
  }
190
+ return newElements;
209
191
  };
210
- }
211
192
 
212
- export const VictoryCursorContainer = cursorContainerMixin(VictoryContainer);
193
+ return {
194
+ props,
195
+ children: [
196
+ ...React.Children.toArray(children),
197
+ ...getCursorElements(),
198
+ ] as React.ReactElement[],
199
+ };
200
+ };
201
+
202
+ export const VictoryCursorContainer = (
203
+ initialProps: VictoryCursorContainerProps,
204
+ ) => {
205
+ const { props, children } = useVictoryCursorContainer(initialProps);
206
+ return <VictoryContainer {...props}>{children}</VictoryContainer>;
207
+ };
208
+
209
+ VictoryCursorContainer.role = "container";
210
+
211
+ VictoryCursorContainer.defaultEvents = (
212
+ initialProps: VictoryCursorContainerProps,
213
+ ) => {
214
+ const props = { ...VICTORY_CURSOR_CONTAINER_DEFAULT_PROPS, ...initialProps };
215
+ const createEventHandler =
216
+ (handler: VictoryEventHandler, disabled?: boolean): VictoryEventHandler =>
217
+ // eslint-disable-next-line max-params
218
+ (event, targetProps, eventKey, context) =>
219
+ disabled || props.disable
220
+ ? {}
221
+ : handler(event, { ...props, ...targetProps }, eventKey, context);
222
+
223
+ return [
224
+ {
225
+ target: "parent",
226
+ eventHandlers: {
227
+ onMouseLeave: createEventHandler(CursorHelpers.onMouseLeave),
228
+ onMouseMove: createEventHandler(CursorHelpers.onMouseMove),
229
+ onTouchMove: createEventHandler(CursorHelpers.onMouseMove),
230
+ },
231
+ },
232
+ ];
233
+ };