Skip to content

Commit 86f2ee4

Browse files
committed
working create-container function
1 parent 995b740 commit 86f2ee4

File tree

7 files changed

+182
-33
lines changed

7 files changed

+182
-33
lines changed

demo/ts/components/create-container-demo.tsx

+4-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { round } from "lodash";
55
import { VictoryChart } from "victory-chart";
66
import { VictoryStack } from "victory-stack";
77
import { VictoryGroup } from "victory-group";
8-
import { createContainer } from "victory-create-container";
8+
import { createContainerFn as createContainer } from "victory-create-container";
99
import { VictoryBar } from "victory-bar";
1010
import { VictoryLine } from "victory-line";
1111
import { VictoryScatter } from "victory-scatter";
@@ -273,10 +273,10 @@ class App extends React.Component {
273273
render() {
274274
return (
275275
<div className="demo">
276-
<Charts behaviors={["zoom", "voronoi"]} />
277-
<Charts behaviors={["zoom", "cursor"]} />
276+
<Charts behaviors={["zoom", "selection"]} />
277+
{/* <Charts behaviors={["zoom", "cursor"]} />
278278
<Charts behaviors={["cursor", "voronoi"]} />
279-
<Charts behaviors={["brush", "voronoi"]} />
279+
<Charts behaviors={["brush", "voronoi"]} /> */}
280280
</div>
281281
);
282282
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
import {
2+
VictoryZoomContainerFn,
3+
useVictoryZoomContainer,
4+
} from "victory-zoom-container";
5+
import {
6+
VictorySelectionContainerFn,
7+
useVictorySelectionContainer,
8+
} from "victory-selection-container";
9+
import React from "react";
10+
import { VictoryContainerFn } from "victory-core";
11+
import { forOwn, groupBy, isEmpty, toPairs } from "lodash";
12+
13+
export type ContainerType =
14+
| "brush"
15+
| "cursor"
16+
| "selection"
17+
| "voronoi"
18+
| "zoom";
19+
20+
const CONTAINERS: {
21+
[key in ContainerType]: {
22+
name: string;
23+
component: React.ComponentType<any>;
24+
hook: (props: any) => {
25+
props: any;
26+
children: React.ReactNode;
27+
};
28+
};
29+
} = {
30+
zoom: {
31+
name: "Zoom",
32+
component: VictoryZoomContainerFn,
33+
hook: useVictoryZoomContainer,
34+
},
35+
selection: {
36+
name: "Selection",
37+
component: VictorySelectionContainerFn,
38+
hook: useVictorySelectionContainer,
39+
},
40+
};
41+
42+
function ensureArray<T>(thing: T): [] | T | T[] {
43+
if (!thing) {
44+
return [];
45+
} else if (!Array.isArray(thing)) {
46+
return [thing];
47+
}
48+
return thing;
49+
}
50+
51+
const combineEventHandlers = (eventHandlersArray: any[]) => {
52+
// takes an array of event handler objects and produces one eventHandlers object
53+
// creates a custom combinedHandler() for events with multiple conflicting handlers
54+
return eventHandlersArray.reduce((localHandlers, finalHandlers) => {
55+
forOwn(localHandlers, (localHandler, eventName) => {
56+
const existingHandler = finalHandlers[eventName];
57+
if (existingHandler) {
58+
// create new handler for event that concats the existing handler's mutations with new ones
59+
finalHandlers[eventName] = function combinedHandler(...params) {
60+
// named for debug clarity
61+
// sometimes handlers return undefined; use empty array instead, for concat()
62+
const existingMutations = ensureArray(existingHandler(...params));
63+
const localMutations = ensureArray(localHandler(...params));
64+
return existingMutations.concat(localMutations);
65+
};
66+
} else {
67+
finalHandlers[eventName] = localHandler;
68+
}
69+
});
70+
return finalHandlers;
71+
});
72+
};
73+
74+
const combineDefaultEvents = (defaultEvents: any[]) => {
75+
// takes a defaultEvents array and returns one equal or lesser length,
76+
// by combining any events that have the same target
77+
const eventsByTarget = groupBy(defaultEvents, "target");
78+
const events = toPairs(eventsByTarget).map(([target, eventsArray]) => {
79+
const newEventsArray = eventsArray.filter(Boolean);
80+
return isEmpty(newEventsArray)
81+
? null
82+
: {
83+
target,
84+
eventHandlers: combineEventHandlers(
85+
eventsArray.map((event) => event.eventHandlers),
86+
),
87+
// note: does not currently handle eventKey or childName
88+
};
89+
});
90+
return events.filter(Boolean);
91+
};
92+
93+
// TODO: Type this function properly
94+
export function createContainerFn(
95+
containerA: ContainerType,
96+
containerB: ContainerType,
97+
) {
98+
const {
99+
name: containerAName,
100+
component: ContainerA,
101+
hook: useContainerA,
102+
} = CONTAINERS[containerA];
103+
const {
104+
name: containerBName,
105+
component: ContainerB,
106+
hook: useContainerB,
107+
} = CONTAINERS[containerB];
108+
109+
function NewContainer(props: any) {
110+
const { children: childrenA, props: propsA } = useContainerA(props);
111+
const { children: childrenB, props: propsB } = useContainerB({
112+
...propsA,
113+
children: childrenA,
114+
});
115+
116+
return <VictoryContainerFn {...propsB}>{childrenB}</VictoryContainerFn>;
117+
}
118+
119+
NewContainer.displayName = `Victory${containerAName}${containerBName}Container`;
120+
NewContainer.role = "container";
121+
NewContainer.defaultEvents = (props: any) =>
122+
combineDefaultEvents([
123+
...ContainerA.defaultEvents(props),
124+
...ContainerB.defaultEvents(props),
125+
]);
126+
127+
return NewContainer;
128+
}
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export * from "./create-container";
2+
export { createContainerFn } from "./create-container-fn";
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
export * from "./victory-selection-container";
2-
export { VictorySelectionContainerFn } from "./victory-selection-container-fn";
2+
export {
3+
VictorySelectionContainerFn,
4+
useVictorySelectionContainer,
5+
} from "./victory-selection-container-fn";
36
export * from "./selection-helpers";

packages/victory-selection-container/src/victory-selection-container-fn.tsx

+23-16
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ import {
77
} from "victory-core";
88
import { SelectionHelpers } from "./selection-helpers";
99

10+
type Handler = (
11+
event: any,
12+
targetProps: any,
13+
eventKey?: any,
14+
context?: any,
15+
) => void;
16+
1017
export interface VictorySelectionContainerProps extends VictoryContainerProps {
1118
activateSelectedData?: boolean;
1219
allowSelection?: boolean;
@@ -31,13 +38,6 @@ export interface VictorySelectionContainerProps extends VictoryContainerProps {
3138
selectionStyle?: React.CSSProperties;
3239
}
3340

34-
type Handler = (
35-
event: any,
36-
targetProps: any,
37-
eventKey?: any,
38-
context?: any,
39-
) => void;
40-
4141
const defaultProps = {
4242
activateSelectedData: true,
4343
allowSelection: true,
@@ -49,7 +49,7 @@ const defaultProps = {
4949
},
5050
};
5151

52-
export const VictorySelectionContainerFn = (
52+
export const useVictorySelectionContainer = (
5353
initialProps: VictorySelectionContainerProps,
5454
) => {
5555
const props = { ...defaultProps, ...initialProps };
@@ -63,21 +63,28 @@ export const VictorySelectionContainerFn = (
6363

6464
const shouldRenderRect = y1 && y2 && x1 && x2;
6565

66-
return (
67-
<VictoryContainerFn {...props}>
68-
{children}
69-
70-
{shouldRenderRect &&
66+
return {
67+
props,
68+
children: [
69+
children,
70+
shouldRenderRect &&
7171
React.cloneElement(selectionComponent, {
7272
key: `${name}-selection`,
7373
x,
7474
y,
7575
width,
7676
height,
7777
style: selectionStyle,
78-
})}
79-
</VictoryContainerFn>
80-
);
78+
}),
79+
],
80+
};
81+
};
82+
83+
export const VictorySelectionContainerFn = (
84+
initialProps: VictorySelectionContainerProps,
85+
) => {
86+
const { props, children } = useVictorySelectionContainer(initialProps);
87+
return <VictoryContainerFn {...props}>{children}</VictoryContainerFn>;
8188
};
8289

8390
VictorySelectionContainerFn.role = "container";
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
export * from "./victory-zoom-container";
2-
export { VictoryZoomContainerFn } from "./victory-zoom-container-fn";
2+
export {
3+
VictoryZoomContainerFn,
4+
useVictoryZoomContainer,
5+
} from "./victory-zoom-container-fn";
36
export * from "./zoom-helpers";

packages/victory-zoom-container/src/victory-zoom-container-fn.tsx

+18-11
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,29 @@ import React from "react";
22
import { ZoomHelpers } from "./zoom-helpers";
33
import {
44
VictoryClipContainer,
5-
Data,
65
VictoryContainerProps,
76
DomainTuple,
87
VictoryContainerFn,
8+
Data,
99
} from "victory-core";
1010
import { defaults } from "lodash";
1111

1212
const DEFAULT_DOWNSAMPLE = 150;
1313

1414
export type ZoomDimensionType = "x" | "y";
1515

16-
type ZoomDomain = {
16+
export type ZoomDomain = {
1717
x: DomainTuple;
1818
y: DomainTuple;
1919
};
2020

21+
type Handler = (
22+
event: any,
23+
targetProps: any,
24+
eventKey?: any,
25+
context?: any,
26+
) => void;
27+
2128
export interface VictoryZoomContainerProps extends VictoryContainerProps {
2229
allowPan?: boolean;
2330
allowZoom?: boolean;
@@ -33,21 +40,14 @@ export interface VictoryZoomContainerProps extends VictoryContainerProps {
3340
zoomDomain?: Partial<ZoomDomain>;
3441
}
3542

36-
type Handler = (
37-
event: any,
38-
targetProps: any,
39-
eventKey?: any,
40-
context?: any,
41-
) => void;
42-
4343
const defaultProps = {
4444
clipContainerComponent: <VictoryClipContainer />,
4545
allowPan: true,
4646
allowZoom: true,
4747
zoomActive: false,
4848
};
4949

50-
export const VictoryZoomContainerFn = (
50+
export const useVictoryZoomContainer = (
5151
initialProps: VictoryZoomContainerProps,
5252
) => {
5353
const props = { ...defaultProps, ...initialProps };
@@ -183,7 +183,14 @@ export const VictoryZoomContainerFn = (
183183
return newChild;
184184
});
185185

186-
return <VictoryContainerFn {...props}>{modifiedChildren}</VictoryContainerFn>;
186+
return { props, children: modifiedChildren };
187+
};
188+
189+
export const VictoryZoomContainerFn = (
190+
initialProps: VictoryZoomContainerProps,
191+
) => {
192+
const { props, children } = useVictoryZoomContainer(initialProps);
193+
return <VictoryContainerFn {...props}>{children}</VictoryContainerFn>;
187194
};
188195

189196
VictoryZoomContainerFn.role = "container";

0 commit comments

Comments
 (0)