Skip to content

Commit 23c3250

Browse files
authored
Containers and portal refactor (#2799)
1 parent be3d76b commit 23c3250

33 files changed

+1871
-1872
lines changed

.changeset/giant-carrots-own.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
"victory": minor
3+
"victory-brush-container": minor
4+
"victory-core": minor
5+
"victory-create-container": minor
6+
"victory-cursor-container": minor
7+
"victory-native": minor
8+
"victory-selection-container": minor
9+
"victory-tooltip": minor
10+
"victory-voronoi-container": minor
11+
"victory-zoom-container": minor
12+
---
13+
14+
Refactor containers and portal to function components
Lines changed: 175 additions & 172 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import React from "react";
22
import {
3-
VictoryContainer,
43
Selection,
54
Rect,
65
DomainTuple,
76
VictoryContainerProps,
7+
VictoryContainer,
8+
VictoryEventHandler,
89
} from "victory-core";
910
import { BrushHelpers } from "./brush-helpers";
1011
import { defaults } from "lodash";
@@ -37,186 +38,188 @@ export interface VictoryBrushContainerProps extends VictoryContainerProps {
3738
) => void;
3839
}
3940

40-
type ComponentClass<TProps> = { new (props: TProps): React.Component<TProps> };
41+
interface VictoryBrushContainerMutatedProps extends VictoryBrushContainerProps {
42+
domain: { x: DomainTuple; y: DomainTuple };
43+
currentDomain: { x: DomainTuple; y: DomainTuple } | undefined;
44+
cachedBrushDomain: { x: DomainTuple; y: DomainTuple } | undefined;
45+
}
4146

42-
export function brushContainerMixin<
43-
TBase extends ComponentClass<TProps>,
44-
TProps extends VictoryBrushContainerProps,
45-
>(Base: TBase) {
46-
// @ts-expect-error "TS2545: A mixin class must have a constructor with a single rest parameter of type 'any[]'."
47-
return class VictoryBrushContainer extends Base {
48-
static displayName = "VictoryBrushContainer";
49-
static defaultProps = {
50-
...VictoryContainer.defaultProps,
51-
allowDrag: true,
52-
allowDraw: true,
53-
allowResize: true,
54-
brushComponent: <Rect />,
55-
brushStyle: {
56-
stroke: "transparent",
57-
fill: "black",
58-
fillOpacity: 0.1,
59-
},
60-
handleComponent: <Rect />,
61-
handleStyle: {
62-
stroke: "transparent",
63-
fill: "transparent",
64-
},
65-
handleWidth: 8,
66-
mouseMoveThreshold: 0,
67-
};
47+
export const VICTORY_BRUSH_CONTAINER_DEFAULT_PROPS = {
48+
allowDrag: true,
49+
allowDraw: true,
50+
allowResize: true,
51+
brushComponent: <Rect />,
52+
brushStyle: {
53+
stroke: "transparent",
54+
fill: "black",
55+
fillOpacity: 0.1,
56+
},
57+
handleComponent: <Rect />,
58+
handleStyle: {
59+
stroke: "transparent",
60+
fill: "transparent",
61+
},
62+
handleWidth: 8,
63+
mouseMoveThreshold: 0,
64+
};
6865

69-
static defaultEvents(props) {
70-
return [
71-
{
72-
target: "parent",
73-
eventHandlers: {
74-
onMouseDown: (evt, targetProps) => {
75-
return props.disable
76-
? {}
77-
: BrushHelpers.onMouseDown(evt, targetProps);
78-
},
79-
onTouchStart: (evt, targetProps) => {
80-
return props.disable
81-
? {}
82-
: BrushHelpers.onMouseDown(evt, targetProps);
83-
},
84-
onGlobalMouseMove: (evt, targetProps) => {
85-
return props.disable ||
86-
(!targetProps.isPanning && !targetProps.isSelecting)
87-
? {}
88-
: BrushHelpers.onGlobalMouseMove(evt, targetProps);
89-
},
90-
onGlobalTouchMove: (evt, targetProps) => {
91-
return props.disable ||
92-
(!targetProps.isPanning && !targetProps.isSelecting)
93-
? {}
94-
: BrushHelpers.onGlobalMouseMove(evt, targetProps);
95-
},
96-
onGlobalMouseUp: (evt, targetProps) => {
97-
return props.disable
98-
? {}
99-
: BrushHelpers.onGlobalMouseUp(evt, targetProps);
100-
},
101-
onGlobalTouchEnd: (evt, targetProps) => {
102-
return props.disable
103-
? {}
104-
: BrushHelpers.onGlobalMouseUp(evt, targetProps);
105-
},
106-
onGlobalTouchCancel: (evt, targetProps) => {
107-
return props.disable
108-
? {}
109-
: BrushHelpers.onGlobalMouseUp(evt, targetProps);
110-
},
111-
},
112-
},
113-
];
114-
}
66+
export const useVictoryBrushContainer = (
67+
initialProps: VictoryBrushContainerProps,
68+
) => {
69+
const props = {
70+
...VICTORY_BRUSH_CONTAINER_DEFAULT_PROPS,
71+
...(initialProps as VictoryBrushContainerMutatedProps),
72+
};
73+
const { children } = props;
11574

116-
getSelectBox(props, coordinates) {
117-
const { x, y } = coordinates;
118-
const { brushStyle, brushComponent, name } = props;
119-
const brushComponentStyle =
120-
brushComponent.props && brushComponent.props.style;
121-
const cursor = !props.allowDrag && !props.allowResize ? "auto" : "move";
122-
return x[0] !== x[1] && y[0] !== y[1]
123-
? React.cloneElement(brushComponent, {
124-
key: `${name}-brush`,
125-
width: Math.abs(x[1] - x[0]) || 1,
126-
height: Math.abs(y[1] - y[0]) || 1,
127-
x: Math.min(x[0], x[1]),
128-
y: Math.min(y[0], y[1]),
129-
cursor,
130-
style: defaults({}, brushComponentStyle, brushStyle),
131-
})
132-
: null;
133-
}
75+
const getSelectBox = (coordinates) => {
76+
const { x, y } = coordinates;
77+
const { brushStyle, brushComponent, name } = props;
78+
const brushComponentStyle =
79+
brushComponent.props && brushComponent.props.style;
80+
const cursor = !props.allowDrag && !props.allowResize ? "auto" : "move";
81+
return x[0] !== x[1] && y[0] !== y[1]
82+
? React.cloneElement(brushComponent, {
83+
key: `${name}-brush`,
84+
width: Math.abs(x[1] - x[0]) || 1,
85+
height: Math.abs(y[1] - y[0]) || 1,
86+
x: Math.min(x[0], x[1]),
87+
y: Math.min(y[0], y[1]),
88+
cursor,
89+
style: defaults({}, brushComponentStyle, brushStyle),
90+
})
91+
: null;
92+
};
13493

135-
getCursorPointers(props) {
136-
const cursors = {
137-
yProps: "ns-resize",
138-
xProps: "ew-resize",
139-
};
140-
if (!props.allowResize && props.allowDrag) {
141-
cursors.xProps = "move";
142-
cursors.yProps = "move";
143-
} else if (!props.allowResize && !props.allowDrag) {
144-
cursors.xProps = "auto";
145-
cursors.yProps = "auto";
146-
}
147-
return cursors;
94+
const getCursorPointers = () => {
95+
const cursors = {
96+
yProps: "ns-resize",
97+
xProps: "ew-resize",
98+
};
99+
if (!props.allowResize && props.allowDrag) {
100+
cursors.xProps = "move";
101+
cursors.yProps = "move";
102+
} else if (!props.allowResize && !props.allowDrag) {
103+
cursors.xProps = "auto";
104+
cursors.yProps = "auto";
148105
}
106+
return cursors;
107+
};
149108

150-
getHandles(props, domain) {
151-
const { handleWidth, handleStyle, handleComponent, name } = props;
152-
const domainBox = BrushHelpers.getDomainBox(props, domain);
153-
const { x1, x2, y1, y2 } = domainBox;
154-
const { top, bottom, left, right } = BrushHelpers.getHandles(
155-
props,
156-
domainBox,
157-
);
158-
const width = Math.abs(x2 - x1) || 1;
159-
const height = Math.abs(y2 - y1) || 1;
160-
const handleComponentStyle =
161-
(handleComponent.props && handleComponent.props.style) || {};
162-
const style = defaults({}, handleComponentStyle, handleStyle);
109+
const getHandles = (domain) => {
110+
const { handleWidth, handleStyle, handleComponent, name } = props;
111+
const domainBox = BrushHelpers.getDomainBox(props, domain);
112+
const { x1, x2, y1, y2 } = domainBox;
113+
const { top, bottom, left, right } = BrushHelpers.getHandles(
114+
props,
115+
domainBox,
116+
);
117+
const width = Math.abs(x2 - x1) || 1;
118+
const height = Math.abs(y2 - y1) || 1;
119+
const handleComponentStyle =
120+
(handleComponent.props && handleComponent.props.style) || {};
121+
const style = defaults({}, handleComponentStyle, handleStyle);
163122

164-
const cursors = this.getCursorPointers(props);
165-
const yProps = {
166-
style,
167-
width,
168-
height: handleWidth,
169-
cursor: cursors.yProps,
170-
};
171-
const xProps = {
172-
style,
173-
width: handleWidth,
174-
height,
175-
cursor: cursors.xProps,
176-
};
123+
const cursors = getCursorPointers();
124+
const yProps = {
125+
style,
126+
width,
127+
height: handleWidth,
128+
cursor: cursors.yProps,
129+
};
130+
const xProps = {
131+
style,
132+
width: handleWidth,
133+
height,
134+
cursor: cursors.xProps,
135+
};
177136

178-
const handleProps = {
179-
top: top && Object.assign({ x: top.x1, y: top.y1 }, yProps),
180-
bottom: bottom && Object.assign({ x: bottom.x1, y: bottom.y1 }, yProps),
181-
left: left && Object.assign({ y: left.y1, x: left.x1 }, xProps),
182-
right: right && Object.assign({ y: right.y1, x: right.x1 }, xProps),
183-
};
184-
const handles = ["top", "bottom", "left", "right"].reduce(
185-
(memo, curr) =>
186-
handleProps[curr]
187-
? memo.concat(
188-
React.cloneElement(
189-
handleComponent,
190-
Object.assign(
191-
{ key: `${name}-handle-${curr}` },
192-
handleProps[curr],
193-
),
137+
const handleProps = {
138+
top: top && Object.assign({ x: top.x1, y: top.y1 }, yProps),
139+
bottom: bottom && Object.assign({ x: bottom.x1, y: bottom.y1 }, yProps),
140+
left: left && Object.assign({ y: left.y1, x: left.x1 }, xProps),
141+
right: right && Object.assign({ y: right.y1, x: right.x1 }, xProps),
142+
};
143+
const handles = ["top", "bottom", "left", "right"].reduce(
144+
(memo, curr) =>
145+
handleProps[curr]
146+
? memo.concat(
147+
React.cloneElement(
148+
handleComponent,
149+
Object.assign(
150+
{ key: `${name}-handle-${curr}` },
151+
handleProps[curr],
194152
),
195-
)
196-
: memo,
197-
[] as React.ReactElement[],
198-
);
199-
return handles.length ? handles : null;
200-
}
153+
),
154+
)
155+
: memo,
156+
[] as React.ReactElement[],
157+
);
158+
return handles.length ? handles : null;
159+
};
201160

202-
getRect(props) {
203-
const { currentDomain, cachedBrushDomain } = props;
204-
const brushDomain = defaults({}, props.brushDomain, props.domain);
205-
const domain = isEqual(brushDomain, cachedBrushDomain)
206-
? defaults({}, currentDomain, brushDomain)
207-
: brushDomain;
208-
const coordinates = Selection.getDomainCoordinates(props, domain);
209-
const selectBox = this.getSelectBox(props, coordinates);
210-
return selectBox ? [selectBox, this.getHandles(props, domain)] : [];
211-
}
161+
const getRect = () => {
162+
const { currentDomain, cachedBrushDomain } = props;
163+
const brushDomain = defaults({}, props.brushDomain, props.domain);
164+
const domain = isEqual(brushDomain, cachedBrushDomain)
165+
? defaults({}, currentDomain, brushDomain)
166+
: brushDomain;
167+
const coordinates = Selection.getDomainCoordinates(props, domain);
168+
const selectBox = getSelectBox(coordinates);
169+
return selectBox ? [selectBox, getHandles(domain)] : [];
170+
};
212171

213-
// Overrides method in VictoryContainer
214-
getChildren(props) {
215-
return [
216-
...React.Children.toArray(props.children),
217-
...this.getRect(props),
218-
];
219-
}
172+
return {
173+
props,
174+
children: [
175+
...React.Children.toArray(children),
176+
...getRect(),
177+
] as React.ReactElement[],
220178
};
221-
}
222-
export const VictoryBrushContainer = brushContainerMixin(VictoryContainer);
179+
};
180+
181+
export const VictoryBrushContainer = (
182+
initialProps: VictoryBrushContainerProps,
183+
) => {
184+
const { props, children } = useVictoryBrushContainer(initialProps);
185+
return <VictoryContainer {...props}>{children}</VictoryContainer>;
186+
};
187+
188+
VictoryBrushContainer.role = "container";
189+
190+
VictoryBrushContainer.defaultEvents = (
191+
initialProps: VictoryBrushContainerProps,
192+
) => {
193+
const props = { ...VICTORY_BRUSH_CONTAINER_DEFAULT_PROPS, ...initialProps };
194+
const createEventHandler =
195+
(
196+
handler: VictoryEventHandler,
197+
isDisabled?: (targetProps: any) => boolean,
198+
): VictoryEventHandler =>
199+
// eslint-disable-next-line max-params
200+
(event, targetProps, eventKey, context) =>
201+
props.disable || isDisabled?.(targetProps)
202+
? {}
203+
: handler(event, { ...props, ...targetProps }, eventKey, context);
204+
205+
return [
206+
{
207+
target: "parent",
208+
eventHandlers: {
209+
onMouseDown: createEventHandler(BrushHelpers.onMouseDown),
210+
onTouchStart: createEventHandler(BrushHelpers.onMouseDown),
211+
onGlobalMouseMove: createEventHandler(
212+
BrushHelpers.onGlobalMouseMove,
213+
(targetProps) => !targetProps.isPanning && !targetProps.isSelecting,
214+
),
215+
onGlobalTouchMove: createEventHandler(
216+
BrushHelpers.onGlobalMouseMove,
217+
(targetProps) => !targetProps.isPanning && !targetProps.isSelecting,
218+
),
219+
onGlobalMouseUp: createEventHandler(BrushHelpers.onGlobalMouseUp),
220+
onGlobalTouchEnd: createEventHandler(BrushHelpers.onGlobalMouseUp),
221+
onGlobalTouchCancel: createEventHandler(BrushHelpers.onGlobalMouseUp),
222+
},
223+
},
224+
];
225+
};

0 commit comments

Comments
 (0)