victory-core 36.9.2-next.3 → 36.9.2

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.
Files changed (147) hide show
  1. package/CHANGELOG.md +22 -10
  2. package/README.md +1 -1
  3. package/dist/victory-core.js +124 -493
  4. package/dist/victory-core.min.js +1 -1
  5. package/es/index.d.ts +17 -17
  6. package/es/types/callbacks.d.ts +36 -36
  7. package/es/types/prop-types.d.ts +129 -129
  8. package/es/victory-accessible-group/victory-accessible-group.d.ts +10 -10
  9. package/es/victory-animation/util.d.ts +66 -66
  10. package/es/victory-animation/victory-animation.d.ts +34 -34
  11. package/es/victory-clip-container/victory-clip-container.d.ts +46 -46
  12. package/es/victory-container/victory-container.d.ts +68 -68
  13. package/es/victory-label/victory-label.d.ts +58 -58
  14. package/es/victory-portal/portal-context.d.ts +11 -11
  15. package/es/victory-portal/portal.d.ts +20 -20
  16. package/es/victory-portal/victory-portal.d.ts +26 -26
  17. package/es/victory-primitives/arc.d.ts +14 -14
  18. package/es/victory-primitives/background.d.ts +13 -13
  19. package/es/victory-primitives/border.d.ts +10 -10
  20. package/es/victory-primitives/circle.d.ts +3 -3
  21. package/es/victory-primitives/clip-path.d.ts +7 -7
  22. package/es/victory-primitives/index.d.ts +14 -14
  23. package/es/victory-primitives/line-segment.d.ts +11 -11
  24. package/es/victory-primitives/line.d.ts +3 -3
  25. package/es/victory-primitives/path.d.ts +3 -3
  26. package/es/victory-primitives/point.d.ts +13 -13
  27. package/es/victory-primitives/rect.d.ts +3 -3
  28. package/es/victory-primitives/text.d.ts +8 -8
  29. package/es/victory-primitives/tspan.d.ts +3 -3
  30. package/es/victory-primitives/types.d.ts +7 -7
  31. package/es/victory-primitives/whisker.d.ts +15 -15
  32. package/es/victory-theme/grayscale.d.ts +2 -2
  33. package/es/victory-theme/material.d.ts +2 -2
  34. package/es/victory-theme/types.d.ts +238 -238
  35. package/es/victory-theme/victory-theme.d.ts +5 -5
  36. package/es/victory-transition/victory-transition.d.ts +53 -53
  37. package/es/victory-util/add-events.d.ts +126 -126
  38. package/es/victory-util/add-events.js +4 -8
  39. package/es/victory-util/axis.d.ts +50 -50
  40. package/es/victory-util/axis.js +13 -6
  41. package/es/victory-util/collection.d.ts +15 -8
  42. package/es/victory-util/collection.js +16 -0
  43. package/es/victory-util/common-props.d.ts +79 -79
  44. package/es/victory-util/data.d.ts +74 -74
  45. package/es/victory-util/default-transitions.d.ts +4 -4
  46. package/es/victory-util/domain.d.ts +90 -90
  47. package/es/victory-util/events.d.ts +64 -64
  48. package/es/victory-util/helpers.d.ts +96 -91
  49. package/es/victory-util/helpers.js +12 -1
  50. package/es/victory-util/hooks/index.d.ts +2 -2
  51. package/es/victory-util/hooks/use-animation-state.d.ts +21 -21
  52. package/es/victory-util/hooks/use-previous-props.d.ts +1 -1
  53. package/es/victory-util/immutable.d.ts +11 -11
  54. package/es/victory-util/index.d.ts +26 -26
  55. package/es/victory-util/label-helpers.d.ts +26 -26
  56. package/es/victory-util/line-helpers.d.ts +4 -4
  57. package/es/victory-util/log.d.ts +1 -1
  58. package/es/victory-util/point-path-helpers.d.ts +9 -9
  59. package/es/victory-util/scale.d.ts +9 -9
  60. package/es/victory-util/selection.d.ts +28 -28
  61. package/es/victory-util/style.d.ts +18 -18
  62. package/es/victory-util/textsize.d.ts +35 -35
  63. package/es/victory-util/timer-context.d.ts +11 -11
  64. package/es/victory-util/timer.d.ts +16 -16
  65. package/es/victory-util/transitions.d.ts +48 -48
  66. package/es/victory-util/type-helpers.d.ts +9 -9
  67. package/es/victory-util/user-props.d.ts +26 -26
  68. package/es/victory-util/wrapper.d.ts +33 -37
  69. package/es/victory-util/wrapper.js +2 -2
  70. package/lib/index.d.ts +17 -17
  71. package/lib/types/callbacks.d.ts +36 -36
  72. package/lib/types/prop-types.d.ts +129 -129
  73. package/lib/victory-accessible-group/victory-accessible-group.d.ts +10 -10
  74. package/lib/victory-animation/util.d.ts +66 -66
  75. package/lib/victory-animation/victory-animation.d.ts +34 -34
  76. package/lib/victory-clip-container/victory-clip-container.d.ts +46 -46
  77. package/lib/victory-container/victory-container.d.ts +68 -68
  78. package/lib/victory-label/victory-label.d.ts +58 -58
  79. package/lib/victory-portal/portal-context.d.ts +11 -11
  80. package/lib/victory-portal/portal.d.ts +20 -20
  81. package/lib/victory-portal/victory-portal.d.ts +26 -26
  82. package/lib/victory-primitives/arc.d.ts +14 -14
  83. package/lib/victory-primitives/background.d.ts +13 -13
  84. package/lib/victory-primitives/border.d.ts +10 -10
  85. package/lib/victory-primitives/circle.d.ts +3 -3
  86. package/lib/victory-primitives/clip-path.d.ts +7 -7
  87. package/lib/victory-primitives/index.d.ts +14 -14
  88. package/lib/victory-primitives/line-segment.d.ts +11 -11
  89. package/lib/victory-primitives/line.d.ts +3 -3
  90. package/lib/victory-primitives/path.d.ts +3 -3
  91. package/lib/victory-primitives/point.d.ts +13 -13
  92. package/lib/victory-primitives/rect.d.ts +3 -3
  93. package/lib/victory-primitives/text.d.ts +8 -8
  94. package/lib/victory-primitives/tspan.d.ts +3 -3
  95. package/lib/victory-primitives/types.d.ts +7 -7
  96. package/lib/victory-primitives/whisker.d.ts +15 -15
  97. package/lib/victory-theme/grayscale.d.ts +2 -2
  98. package/lib/victory-theme/material.d.ts +2 -2
  99. package/lib/victory-theme/types.d.ts +238 -238
  100. package/lib/victory-theme/victory-theme.d.ts +5 -5
  101. package/lib/victory-transition/victory-transition.d.ts +53 -53
  102. package/lib/victory-util/add-events.d.ts +126 -126
  103. package/lib/victory-util/add-events.js +6 -6
  104. package/lib/victory-util/axis.d.ts +50 -50
  105. package/lib/victory-util/axis.js +13 -7
  106. package/lib/victory-util/collection.d.ts +15 -8
  107. package/lib/victory-util/collection.js +18 -0
  108. package/lib/victory-util/common-props.d.ts +79 -79
  109. package/lib/victory-util/data.d.ts +74 -74
  110. package/lib/victory-util/default-transitions.d.ts +4 -4
  111. package/lib/victory-util/domain.d.ts +90 -90
  112. package/lib/victory-util/events.d.ts +64 -64
  113. package/lib/victory-util/helpers.d.ts +96 -91
  114. package/lib/victory-util/helpers.js +13 -0
  115. package/lib/victory-util/hooks/index.d.ts +2 -2
  116. package/lib/victory-util/hooks/use-animation-state.d.ts +21 -21
  117. package/lib/victory-util/hooks/use-previous-props.d.ts +1 -1
  118. package/lib/victory-util/immutable.d.ts +11 -11
  119. package/lib/victory-util/index.d.ts +26 -26
  120. package/lib/victory-util/label-helpers.d.ts +26 -26
  121. package/lib/victory-util/line-helpers.d.ts +4 -4
  122. package/lib/victory-util/log.d.ts +1 -1
  123. package/lib/victory-util/point-path-helpers.d.ts +9 -9
  124. package/lib/victory-util/scale.d.ts +9 -9
  125. package/lib/victory-util/selection.d.ts +28 -28
  126. package/lib/victory-util/style.d.ts +18 -18
  127. package/lib/victory-util/textsize.d.ts +35 -35
  128. package/lib/victory-util/timer-context.d.ts +11 -11
  129. package/lib/victory-util/timer.d.ts +16 -16
  130. package/lib/victory-util/transitions.d.ts +48 -48
  131. package/lib/victory-util/type-helpers.d.ts +9 -9
  132. package/lib/victory-util/user-props.d.ts +26 -26
  133. package/lib/victory-util/wrapper.d.ts +33 -37
  134. package/lib/victory-util/wrapper.js +2 -2
  135. package/package.json +6 -3
  136. package/src/types/prop-types.ts +0 -7
  137. package/src/victory-container/victory-container.tsx +195 -171
  138. package/src/victory-portal/portal-context.ts +4 -5
  139. package/src/victory-portal/portal.tsx +42 -5
  140. package/src/victory-portal/victory-portal.tsx +71 -34
  141. package/src/victory-util/add-events.tsx +6 -4
  142. package/src/victory-util/axis.tsx +12 -3
  143. package/src/victory-util/collection.tsx +13 -0
  144. package/src/victory-util/helpers.ts +11 -0
  145. package/src/victory-util/index.ts +0 -1
  146. package/src/victory-util/wrapper.tsx +1 -0
  147. package/src/victory-util/merge-refs.ts +0 -13
@@ -1,12 +1,13 @@
1
- import React, { useRef } from "react";
2
- import { uniqueId } from "lodash";
1
+ import React from "react";
2
+ import { defaults, uniqueId, isObject } from "lodash";
3
3
  import { Portal } from "../victory-portal/portal";
4
4
  import { PortalContext } from "../victory-portal/portal-context";
5
+ import TimerContext from "../victory-util/timer-context";
6
+ import * as Helpers from "../victory-util/helpers";
5
7
  import * as UserProps from "../victory-util/user-props";
6
8
  import { OriginType } from "../victory-label/victory-label";
7
9
  import { D3Scale } from "../types/prop-types";
8
10
  import { VictoryThemeDefinition } from "../victory-theme/types";
9
- import { mergeRefs } from "../victory-util";
10
11
 
11
12
  export interface VictoryContainerProps {
12
13
  "aria-describedby"?: string;
@@ -20,6 +21,9 @@ export interface VictoryContainerProps {
20
21
  height?: number;
21
22
  name?: string;
22
23
  origin?: OriginType;
24
+ ouiaId?: number | string;
25
+ ouiaSafe?: boolean;
26
+ ouiaType?: string;
23
27
  polar?: boolean;
24
28
  portalComponent?: React.ReactElement;
25
29
  portalZIndex?: number;
@@ -35,181 +39,201 @@ export interface VictoryContainerProps {
35
39
  theme?: VictoryThemeDefinition;
36
40
  title?: string;
37
41
  width?: number;
38
- // Props defined by the Open UI Automation (OUIA) 1.0-RC spec
39
- // See https://ouia.readthedocs.io/en/latest/README.html#ouia-component
40
- ouiaId?: number | string;
41
- ouiaSafe?: boolean;
42
- ouiaType?: string;
43
42
  }
44
43
 
45
- const defaultProps = {
46
- className: "VictoryContainer",
47
- portalComponent: <Portal />,
48
- portalZIndex: 99,
49
- responsive: true,
50
- role: "img",
51
- };
52
-
53
- export function useVictoryContainer<TProps extends VictoryContainerProps>(
54
- initialProps: TProps,
55
- ) {
56
- const props = { ...defaultProps, ...initialProps };
57
- const { title, desc, width, height, responsive } = props;
58
-
59
- const localContainerRef = useRef<HTMLDivElement>(null);
60
-
61
- const [portalElement, setPortalElement] = React.useState<SVGSVGElement>();
62
-
63
- const portalRef = (element: SVGSVGElement) => setPortalElement(element);
64
-
65
- // Generated ID stored in ref because it needs to persist across renders
66
- const generatedId = useRef(uniqueId("victory-container-"));
67
- const containerId = props.containerId ?? generatedId.current;
68
-
69
- const getIdForElement = (elName: string) => `${containerId}-${elName}`;
70
-
71
- const userProps = UserProps.getSafeUserProps(props);
72
-
73
- const dimensions = responsive
74
- ? { width: "100%", height: "100%" }
75
- : { width, height };
76
-
77
- const viewBox = responsive ? `0 0 ${width} ${height}` : undefined;
78
-
79
- const preserveAspectRatio = responsive
80
- ? props.preserveAspectRatio
81
- : undefined;
82
-
83
- const ariaLabelledBy =
84
- [title && getIdForElement("title"), props["aria-labelledby"]]
85
- .filter(Boolean)
86
- .join(" ") || undefined;
87
-
88
- const ariaDescribedBy =
89
- [desc && getIdForElement("desc"), props["aria-describedby"]]
90
- .filter(Boolean)
91
- .join(" ") || undefined;
92
-
93
- const titleId = getIdForElement("title");
94
- const descId = getIdForElement("desc");
95
-
96
- return {
97
- ...props,
98
- titleId,
99
- descId,
100
- dimensions,
101
- viewBox,
102
- preserveAspectRatio,
103
- ariaLabelledBy,
104
- ariaDescribedBy,
105
- userProps,
106
- portalRef,
107
- portalElement,
108
- localContainerRef,
44
+ export class VictoryContainer<
45
+ TProps extends VictoryContainerProps,
46
+ > extends React.Component<TProps> {
47
+ static displayName = "VictoryContainer";
48
+ static role = "container";
49
+
50
+ static defaultProps = {
51
+ className: "VictoryContainer",
52
+ portalComponent: <Portal />,
53
+ portalZIndex: 99,
54
+ responsive: true,
55
+ role: "img",
56
+ };
57
+
58
+ static contextType = TimerContext;
59
+ private containerId: VictoryContainerProps["containerId"];
60
+ // @ts-expect-error Ref will be initialized on mount
61
+ private portalRef: Portal;
62
+ // @ts-expect-error Ref will be initialized on mount
63
+ private containerRef: HTMLElement;
64
+ private shouldHandleWheel: boolean;
65
+
66
+ constructor(props: TProps) {
67
+ super(props);
68
+ this.containerId =
69
+ !isObject(props) || props.containerId === undefined
70
+ ? uniqueId("victory-container-")
71
+ : props.containerId;
72
+
73
+ this.shouldHandleWheel = !!(props && props.events && props.events.onWheel);
74
+ }
75
+ savePortalRef = (portal) => {
76
+ this.portalRef = portal;
77
+ return portal;
78
+ };
79
+ portalUpdate = (key, el) => this.portalRef.portalUpdate(key, el);
80
+ portalRegister = () => this.portalRef.portalRegister();
81
+ portalDeregister = (key) => this.portalRef.portalDeregister(key);
82
+
83
+ saveContainerRef = (container: HTMLElement) => {
84
+ if (Helpers.isFunction(this.props.containerRef)) {
85
+ this.props.containerRef(container);
86
+ }
87
+ this.containerRef = container;
88
+ return container;
109
89
  };
110
- }
111
90
 
112
- export const VictoryContainer = (initialProps: VictoryContainerProps) => {
113
- const {
114
- role,
115
- title,
116
- desc,
117
- children,
118
- className,
119
- portalZIndex,
120
- portalComponent,
121
- width,
122
- height,
123
- style,
124
- tabIndex,
125
- responsive,
126
- events,
127
- ouiaId,
128
- ouiaSafe,
129
- ouiaType,
130
- dimensions,
131
- ariaDescribedBy,
132
- ariaLabelledBy,
133
- viewBox,
134
- preserveAspectRatio,
135
- userProps,
136
- titleId,
137
- descId,
138
- portalElement,
139
- portalRef,
140
- containerRef,
141
- localContainerRef,
142
- } = useVictoryContainer(initialProps);
143
-
144
- React.useEffect(() => {
145
- if (!events?.onWheel) return;
146
-
147
- const handleWheel = (e: WheelEvent) => e.preventDefault();
148
-
149
- const container = localContainerRef?.current;
150
- container?.addEventListener("wheel", handleWheel);
151
-
152
- return () => {
153
- container?.removeEventListener("wheel", handleWheel);
91
+ handleWheel = (e) => e.preventDefault();
92
+
93
+ componentDidMount() {
94
+ if (this.shouldHandleWheel && this.containerRef) {
95
+ this.containerRef.addEventListener("wheel", this.handleWheel);
96
+ }
97
+ }
98
+
99
+ componentWillUnmount() {
100
+ if (this.shouldHandleWheel && this.containerRef) {
101
+ this.containerRef.removeEventListener("wheel", this.handleWheel);
102
+ }
103
+ }
104
+
105
+ getIdForElement(elementName) {
106
+ return `${this.containerId}-${elementName}`;
107
+ }
108
+
109
+ // overridden in custom containers
110
+ getChildren(props) {
111
+ return props.children;
112
+ }
113
+
114
+ // Get props defined by the Open UI Automation (OUIA) 1.0-RC spec
115
+ // See https://ouia.readthedocs.io/en/latest/README.html#ouia-component
116
+ getOUIAProps(props) {
117
+ const { ouiaId, ouiaSafe, ouiaType } = props;
118
+ return {
119
+ ...(ouiaId && { "data-ouia-component-id": ouiaId }),
120
+ ...(ouiaType && { "data-ouia-component-type": ouiaType }),
121
+ ...(ouiaSafe !== undefined && { "data-ouia-safe": ouiaSafe }),
122
+ };
123
+ }
124
+
125
+ renderContainer(props, svgProps, style) {
126
+ const {
127
+ title,
128
+ desc,
129
+ portalComponent,
130
+ className,
131
+ width,
132
+ height,
133
+ portalZIndex,
134
+ responsive,
135
+ } = props;
136
+ const children = this.getChildren(props);
137
+ const dimensions = responsive
138
+ ? { width: "100%", height: "100%" }
139
+ : { width, height };
140
+ const divStyle = Object.assign(
141
+ {
142
+ pointerEvents: "none",
143
+ touchAction: "none",
144
+ position: "relative",
145
+ } as const,
146
+ dimensions,
147
+ );
148
+ const portalDivStyle = Object.assign(
149
+ { zIndex: portalZIndex, position: "absolute", top: 0, left: 0 } as const,
150
+ dimensions,
151
+ );
152
+ const svgStyle = Object.assign({ pointerEvents: "all" }, dimensions);
153
+ const portalSvgStyle = Object.assign({ overflow: "visible" }, dimensions);
154
+ const portalProps = {
155
+ width,
156
+ height,
157
+ viewBox: svgProps.viewBox,
158
+ preserveAspectRatio: svgProps.preserveAspectRatio,
159
+ style: portalSvgStyle,
154
160
  };
155
- // eslint-disable-next-line react-hooks/exhaustive-deps
156
- }, []);
157
-
158
- return (
159
- <PortalContext.Provider value={{ portalElement }}>
160
- <div
161
- className={className}
162
- style={{
163
- ...style,
164
- width: responsive ? style?.width : dimensions.width,
165
- height: responsive ? style?.height : dimensions.height,
166
- pointerEvents: "none",
167
- touchAction: "none",
168
- position: "relative",
161
+ return (
162
+ <PortalContext.Provider
163
+ value={{
164
+ portalUpdate: this.portalUpdate,
165
+ portalRegister: this.portalRegister,
166
+ portalDeregister: this.portalDeregister,
169
167
  }}
170
- data-ouia-component-id={ouiaId}
171
- data-ouia-component-type={ouiaType}
172
- data-ouia-safe={ouiaSafe}
173
- ref={mergeRefs([localContainerRef, containerRef])}
174
168
  >
175
- <svg
176
- width={width}
177
- height={height}
178
- tabIndex={tabIndex}
179
- role={role}
180
- aria-labelledby={ariaLabelledBy}
181
- aria-describedby={ariaDescribedBy}
182
- viewBox={viewBox}
183
- preserveAspectRatio={preserveAspectRatio}
184
- style={{ ...dimensions, pointerEvents: "all" }}
185
- {...userProps}
186
- {...events}
187
- >
188
- {title ? <title id={titleId}>{title}</title> : null}
189
- {desc ? <desc id={descId}>{desc}</desc> : null}
190
- {children}
191
- </svg>
192
169
  <div
193
- style={{
194
- ...dimensions,
195
- zIndex: portalZIndex,
196
- position: "absolute",
197
- top: 0,
198
- left: 0,
199
- }}
170
+ style={defaults({}, style, divStyle)}
171
+ className={className}
172
+ ref={this.saveContainerRef}
173
+ {...this.getOUIAProps(props)}
200
174
  >
201
- {React.cloneElement(portalComponent, {
202
- width,
203
- height,
204
- viewBox,
205
- preserveAspectRatio,
206
- style: { ...dimensions, overflow: "visible" },
207
- ref: portalRef,
208
- })}
175
+ <svg {...svgProps} style={svgStyle}>
176
+ {title ? (
177
+ <title id={this.getIdForElement("title")}>{title}</title>
178
+ ) : null}
179
+ {desc ? (
180
+ <desc id={this.getIdForElement("desc")}>{desc}</desc>
181
+ ) : null}
182
+ {children}
183
+ </svg>
184
+ <div style={portalDivStyle}>
185
+ {React.cloneElement(portalComponent, {
186
+ ...portalProps,
187
+ ref: this.savePortalRef,
188
+ })}
189
+ </div>
209
190
  </div>
210
- </div>
211
- </PortalContext.Provider>
212
- );
213
- };
214
-
215
- VictoryContainer.role = "container";
191
+ </PortalContext.Provider>
192
+ );
193
+ }
194
+
195
+ render() {
196
+ const {
197
+ width,
198
+ height,
199
+ responsive,
200
+ events,
201
+ title,
202
+ desc,
203
+ tabIndex,
204
+ preserveAspectRatio,
205
+ role,
206
+ } = this.props;
207
+
208
+ const style = responsive
209
+ ? this.props.style
210
+ : Helpers.omit(this.props.style!, ["height", "width"]);
211
+
212
+ const userProps = UserProps.getSafeUserProps(this.props);
213
+
214
+ const svgProps = Object.assign(
215
+ {
216
+ width,
217
+ height,
218
+ tabIndex,
219
+ role,
220
+ "aria-labelledby":
221
+ [
222
+ title && this.getIdForElement("title"),
223
+ this.props["aria-labelledby"],
224
+ ]
225
+ .filter(Boolean)
226
+ .join(" ") || undefined,
227
+ "aria-describedby":
228
+ [desc && this.getIdForElement("desc"), this.props["aria-describedby"]]
229
+ .filter(Boolean)
230
+ .join(" ") || undefined,
231
+ viewBox: responsive ? `0 0 ${width} ${height}` : undefined,
232
+ preserveAspectRatio: responsive ? preserveAspectRatio : undefined,
233
+ ...userProps,
234
+ },
235
+ events,
236
+ );
237
+ return this.renderContainer(this.props, svgProps, style);
238
+ }
239
+ }
@@ -1,15 +1,14 @@
1
1
  import React from "react";
2
2
 
3
3
  export interface PortalContextValue {
4
- portalElement: SVGSVGElement | undefined;
4
+ portalRegister(): number;
5
+ portalUpdate(key: number, element: React.ReactElement): void;
6
+ portalDeregister(key: number): void;
5
7
  }
6
8
 
7
9
  /**
8
10
  * The React context object consumers may use to access the context of the
9
11
  * portal.
10
12
  */
11
- export const PortalContext = React.createContext<
12
- PortalContextValue | undefined
13
- >(undefined);
14
-
13
+ export const PortalContext = React.createContext({} as PortalContextValue);
15
14
  PortalContext.displayName = "PortalContext";
@@ -1,4 +1,5 @@
1
1
  import React from "react";
2
+ import { PortalContextValue } from "./portal-context";
2
3
 
3
4
  export interface PortalProps {
4
5
  className?: string;
@@ -8,8 +9,44 @@ export interface PortalProps {
8
9
  width?: number;
9
10
  }
10
11
 
11
- export const Portal = React.forwardRef<SVGSVGElement, PortalProps>(
12
- (props, ref) => {
13
- return <svg ref={ref} {...props} />;
14
- },
15
- );
12
+ export class Portal
13
+ extends React.Component<PortalProps>
14
+ implements PortalContextValue
15
+ {
16
+ static displayName = "Portal";
17
+
18
+ private readonly map: Record<string, React.ReactElement>;
19
+ private index: number;
20
+
21
+ constructor(props: PortalProps) {
22
+ super(props);
23
+ this.map = {};
24
+ this.index = 1;
25
+ }
26
+
27
+ public portalRegister = (): number => {
28
+ return ++this.index;
29
+ };
30
+
31
+ public portalUpdate = (key: number, element: React.ReactElement) => {
32
+ this.map[key] = element;
33
+ this.forceUpdate();
34
+ };
35
+
36
+ public portalDeregister = (key: number) => {
37
+ delete this.map[key];
38
+ this.forceUpdate();
39
+ };
40
+
41
+ public getChildren() {
42
+ return Object.keys(this.map).map((key) => {
43
+ const el = this.map[key];
44
+ return el ? React.cloneElement(el, { key }) : el;
45
+ });
46
+ }
47
+
48
+ // Overridden in victory-core-native
49
+ render() {
50
+ return <svg {...this.props}>{this.getChildren()}</svg>;
51
+ }
52
+ }
@@ -3,47 +3,84 @@ import { defaults } from "lodash";
3
3
  import * as Log from "../victory-util/log";
4
4
  import * as Helpers from "../victory-util/helpers";
5
5
  import { PortalContext } from "./portal-context";
6
- import { createPortal } from "react-dom";
7
6
 
8
7
  export interface VictoryPortalProps {
9
8
  children?: React.ReactElement;
10
9
  groupComponent?: React.ReactElement;
11
10
  }
12
11
 
13
- const defaultProps: VictoryPortalProps = {
14
- groupComponent: <g />,
15
- };
12
+ export interface VictoryPortal {
13
+ context: React.ContextType<typeof PortalContext>;
14
+ }
15
+
16
+ export class VictoryPortal extends React.Component<VictoryPortalProps> {
17
+ static displayName = "VictoryPortal";
18
+
19
+ static role = "portal";
20
+
21
+ static defaultProps = {
22
+ groupComponent: <g />,
23
+ };
24
+
25
+ static contextType = PortalContext;
26
+ private checkedContext!: boolean;
27
+ private portalKey!: number;
28
+ public renderInPlace!: boolean;
29
+ public element!: React.ReactElement;
30
+
31
+ componentDidMount() {
32
+ if (!this.checkedContext) {
33
+ if (typeof this.context.portalUpdate !== "function") {
34
+ const msg =
35
+ "`renderInPortal` is not supported outside of `VictoryContainer`. " +
36
+ "Component will be rendered in place";
37
+ Log.warn(msg);
38
+ this.renderInPlace = true;
39
+ }
40
+ this.checkedContext = true;
41
+ }
42
+ this.forceUpdate();
43
+ }
44
+
45
+ componentDidUpdate() {
46
+ if (!this.renderInPlace) {
47
+ this.portalKey = this.portalKey || this.context.portalRegister();
48
+ this.context.portalUpdate(this.portalKey, this.element);
49
+ }
50
+ }
16
51
 
17
- export const VictoryPortal = (initialProps: VictoryPortalProps) => {
18
- const props = { ...defaultProps, ...initialProps };
19
- const portalContext = React.useContext(PortalContext);
52
+ componentWillUnmount() {
53
+ if (this.context && this.context.portalDeregister) {
54
+ this.context.portalDeregister(this.portalKey);
55
+ }
56
+ }
20
57
 
21
- if (!portalContext) {
22
- const msg =
23
- "`renderInPortal` is not supported outside of `VictoryContainer`. " +
24
- "Component will be rendered in place";
25
- Log.warn(msg);
58
+ // Overridden in victory-core-native
59
+ renderPortal(child: React.ReactElement) {
60
+ if (this.renderInPlace) {
61
+ return child;
62
+ }
63
+ this.element = child;
64
+ return null;
26
65
  }
27
66
 
28
- const children = (
29
- Array.isArray(props.children) ? props.children[0] : props.children
30
- ) as React.ReactElement;
31
- const { groupComponent } = props;
32
- const childProps = (children && children.props) || {};
33
- const standardProps = childProps.groupComponent
34
- ? { groupComponent, standalone: false }
35
- : {};
36
- const newProps = defaults(
37
- standardProps,
38
- childProps,
39
- Helpers.omit(props, ["children", "groupComponent"]),
40
- );
41
- const child = children && React.cloneElement(children, newProps);
42
-
43
- // If there is no portal context, render the child in place
44
- return portalContext?.portalElement
45
- ? createPortal(child, portalContext.portalElement)
46
- : child;
47
- };
48
-
49
- VictoryPortal.role = "portal";
67
+ render() {
68
+ const children = (
69
+ Array.isArray(this.props.children)
70
+ ? this.props.children[0]
71
+ : this.props.children
72
+ ) as React.ReactElement;
73
+ const { groupComponent } = this.props;
74
+ const childProps = (children && children.props) || {};
75
+ const standardProps = childProps.groupComponent
76
+ ? { groupComponent, standalone: false }
77
+ : {};
78
+ const newProps = defaults(
79
+ standardProps,
80
+ childProps,
81
+ Helpers.omit(this.props, ["children", "groupComponent"]),
82
+ );
83
+ const child = children && React.cloneElement(children, newProps);
84
+ return this.renderPortal(child);
85
+ }
86
+ }
@@ -1,11 +1,13 @@
1
1
  import React from "react";
2
- import { defaults, difference, isEmpty, pick } from "lodash";
3
- import type { ComponentEvent } from "./events";
4
- import * as Events from "./events";
2
+ import { defaults, isEmpty, pick } from "lodash";
5
3
  import isEqual from "react-fast-compare";
4
+
5
+ import { VictoryLabelableProps } from "../types/prop-types";
6
6
  import { VictoryTransition } from "../victory-transition/victory-transition";
7
7
  import { VictoryCommonProps, VictoryDatableProps } from "./common-props";
8
- import { VictoryLabelableProps } from "../types/prop-types";
8
+ import { difference } from "./collection";
9
+ import type { ComponentEvent } from "./events";
10
+ import * as Events from "./events";
9
11
  import { isFunction, isNil } from "./helpers";
10
12
 
11
13
  // DISCLAIMER:
@@ -1,10 +1,19 @@
1
1
  import React from "react";
2
- import { defaults, identity, isObject, invert, uniq, orderBy } from "lodash";
2
+ import { defaults, isObject, uniq, orderBy } from "lodash";
3
3
  import * as Collection from "./collection";
4
4
  import * as Domain from "./domain";
5
5
  import * as Helpers from "./helpers";
6
6
  import { D3Scale } from "../types/prop-types";
7
7
 
8
+ /**
9
+ * Returns the first argument it receives
10
+ * @param value The value to return
11
+ * @returns The value given
12
+ */
13
+ function identity<T>(value: T): T {
14
+ return value;
15
+ }
16
+
8
17
  /**
9
18
  * Returns the axis (x or y) of a particular axis component
10
19
  * @param {Object} props: the props object.
@@ -146,7 +155,7 @@ function getDefaultTickFormat(props) {
146
155
  ? (x, index) => tickValues[index]
147
156
  : fallbackFormat;
148
157
  }
149
- const invertedStringMap = stringMap && invert(stringMap);
158
+ const invertedStringMap = stringMap && Helpers.invert(stringMap);
150
159
  const tickValueArray = orderBy(Object.values(stringMap), (n) => n);
151
160
  const dataNames = tickValueArray.map((tick: any) => invertedStringMap[tick]);
152
161
  // string ticks should have one tick of padding at the beginning
@@ -252,7 +261,7 @@ export function getTickFormat(props, scale) {
252
261
  return (x, index) => filteredTickFormat[index];
253
262
  } else if (tickFormat && Helpers.isFunction(tickFormat)) {
254
263
  const applyStringTicks = (tick, index, ticks) => {
255
- const invertedStringMap = invert(stringMap);
264
+ const invertedStringMap = Helpers.invert(stringMap);
256
265
  const stringTickArray = ticks.map((t) => invertedStringMap[t]);
257
266
  return props.tickFormat(invertedStringMap[tick], index, stringTickArray);
258
267
  };
@@ -34,6 +34,19 @@ export function containsOnlyStrings(
34
34
  );
35
35
  }
36
36
 
37
+ /**
38
+ * Creates an array of array values not included in the other given arrays
39
+ * @param a The array to inspect
40
+ * @param b The values to exclude
41
+ * @returns The new array of filtered values
42
+ */
43
+ export function difference<T>(a: Array<T>, b: Array<T>): Array<T> {
44
+ if (a && b) {
45
+ return a.filter((value) => !b.includes(value));
46
+ }
47
+ return [];
48
+ }
49
+
37
50
  export function isArrayOfArrays<T>(
38
51
  collection: Array<T> | Array<Array<T>> | unknown,
39
52
  ): collection is Array<Array<T>> {