@octanejs/recharts 0.1.16 → 0.1.18

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 (88) hide show
  1. package/package.json +4 -4
  2. package/src/animation/CSSTransitionAnimate.tsrx +142 -0
  3. package/src/cartesian/Area.tsrx +1096 -0
  4. package/src/cartesian/Area.tsrx.d.ts +340 -0
  5. package/src/cartesian/AreaRevealShape.tsrx +202 -0
  6. package/src/cartesian/CartesianGrid.tsrx +643 -0
  7. package/src/cartesian/CartesianGrid.tsrx.d.ts +219 -0
  8. package/src/cartesian/ErrorBar.tsrx +322 -0
  9. package/src/cartesian/ErrorBar.tsrx.d.ts +131 -0
  10. package/src/cartesian/Funnel.tsrx +833 -0
  11. package/src/cartesian/Funnel.tsrx.d.ts +274 -0
  12. package/src/cartesian/ReferenceLine.tsrx +452 -0
  13. package/src/cartesian/ReferenceLine.tsrx.d.ts +178 -0
  14. package/src/cartesian/Scatter.tsrx +1076 -0
  15. package/src/cartesian/Scatter.tsrx.d.ts +351 -0
  16. package/src/cartesian/ZAxis.tsrx +148 -0
  17. package/src/cartesian/ZAxis.tsrx.d.ts +102 -0
  18. package/src/chart/AreaChart.tsrx +22 -0
  19. package/src/chart/AreaChart.tsrx.d.ts +12 -0
  20. package/src/chart/ComposedChart.tsrx +22 -0
  21. package/src/chart/ComposedChart.tsrx.d.ts +12 -0
  22. package/src/chart/FunnelChart.tsrx +22 -0
  23. package/src/chart/FunnelChart.tsrx.d.ts +12 -0
  24. package/src/chart/PieChart.tsrx +31 -0
  25. package/src/chart/PieChart.tsrx.d.ts +31 -0
  26. package/src/chart/PolarChart.tsrx +121 -0
  27. package/src/chart/RadarChart.tsrx +53 -0
  28. package/src/chart/RadarChart.tsrx.d.ts +31 -0
  29. package/src/chart/RadialBarChart.tsrx +31 -0
  30. package/src/chart/RadialBarChart.tsrx.d.ts +31 -0
  31. package/src/chart/Sankey.tsrx +1542 -0
  32. package/src/chart/Sankey.tsrx.d.ts +253 -0
  33. package/src/chart/ScatterChart.tsrx +22 -0
  34. package/src/chart/ScatterChart.tsrx.d.ts +12 -0
  35. package/src/chart/SunburstChart.tsrx +495 -0
  36. package/src/chart/SunburstChart.tsrx.d.ts +146 -0
  37. package/src/chart/types.ts +19 -0
  38. package/src/component/Cursor.tsrx +157 -0
  39. package/src/component/DefaultLegendContent.tsrx +288 -0
  40. package/src/component/DefaultLegendContent.tsrx.d.ts +125 -0
  41. package/src/component/DefaultTooltipContent.tsrx +215 -0
  42. package/src/component/DefaultTooltipContent.tsrx.d.ts +87 -0
  43. package/src/component/Legend.tsrx +302 -0
  44. package/src/component/Legend.tsrx.d.ts +88 -0
  45. package/src/component/ResponsiveContainer.ts +1 -22
  46. package/src/component/ResponsiveContainer.tsrx +171 -0
  47. package/src/component/ResponsiveContainer.tsrx.d.ts +81 -0
  48. package/src/component/Tooltip.tsrx +425 -0
  49. package/src/component/Tooltip.tsrx.d.ts +246 -0
  50. package/src/component/TooltipBoundingBox.tsrx +135 -0
  51. package/src/context/CellsContext.ts +12 -0
  52. package/src/context/legendPayloadContext.tsrx +11 -0
  53. package/src/context/useTooltipAxis.ts +20 -0
  54. package/src/index.d.ts +236 -0
  55. package/src/index.ts +67 -0
  56. package/src/polar/Pie.tsrx +1224 -0
  57. package/src/polar/Pie.tsrx.d.ts +436 -0
  58. package/src/polar/PolarAngleAxis.tsrx +554 -0
  59. package/src/polar/PolarAngleAxis.tsrx.d.ts +215 -0
  60. package/src/polar/PolarGrid.tsrx +317 -0
  61. package/src/polar/PolarGrid.tsrx.d.ts +117 -0
  62. package/src/polar/PolarRadiusAxis.tsrx +463 -0
  63. package/src/polar/PolarRadiusAxis.tsrx.d.ts +209 -0
  64. package/src/polar/Radar.tsrx +696 -0
  65. package/src/polar/Radar.tsrx.d.ts +215 -0
  66. package/src/polar/RadialBar.tsrx +887 -0
  67. package/src/polar/RadialBar.tsrx.d.ts +340 -0
  68. package/src/state/ReportPolarOptions.tsrx +11 -0
  69. package/src/state/selectors/areaSelectors.ts +257 -0
  70. package/src/state/selectors/funnelSelectors.ts +86 -0
  71. package/src/state/selectors/pieSelectors.ts +134 -0
  72. package/src/state/selectors/polarGridSelectors.ts +43 -0
  73. package/src/state/selectors/polarScaleSelectors.ts +159 -0
  74. package/src/state/selectors/polarSelectors.ts +198 -0
  75. package/src/state/selectors/radarSelectors.ts +228 -0
  76. package/src/state/selectors/radialBarSelectors.ts +511 -0
  77. package/src/state/selectors/scatterSelectors.ts +168 -0
  78. package/src/util/FunnelUtils.tsrx +19 -0
  79. package/src/util/RadialBarUtils.tsrx +29 -0
  80. package/src/util/ScatterUtils.tsrx +34 -0
  81. package/src/util/cursor/getCursorPoints.ts +45 -0
  82. package/src/util/cursor/getCursorRectangle.ts +28 -0
  83. package/src/util/cursor/getRadialCursorPoints.ts +31 -0
  84. package/src/util/payload/getUniqPayload.ts +28 -0
  85. package/src/util/scale/CartesianScaleHelper.ts +71 -0
  86. package/src/util/tooltip/translate.ts +168 -0
  87. package/src/util/types.ts +3 -0
  88. package/src/util/useElementOffset.ts +147 -0
@@ -1,22 +1 @@
1
- // PARTIAL port of component/ResponsiveContainer.tsx — Phase 1 needs only the
2
- // CONTEXT surface (chartLayoutContext's ReportChartSize prefers container-
3
- // measured dimensions when present). The ResizeObserver-driven container
4
- // component itself is a Phase 2 port (measurement + interaction phase).
5
- import { createContext, useContext } from 'octane';
6
-
7
- export interface ResponsiveContainerDimensions {
8
- width: number;
9
- height: number;
10
- }
11
-
12
- const initialDimension: ResponsiveContainerDimensions = { width: -1, height: -1 };
13
-
14
- // Upstream defaults the context VALUE to the {-1,-1} dimension object (always
15
- // truthy); consumers gate on `.width > 0`. Mirror that exactly.
16
- const ResponsiveContainerContext = createContext<ResponsiveContainerDimensions>(initialDimension);
17
-
18
- export const ResponsiveContainerContextProviderInternal = ResponsiveContainerContext.Provider;
19
-
20
- export const useResponsiveContainerContext = () => useContext(ResponsiveContainerContext);
21
-
22
- export { initialDimension as defaultResponsiveContainerDimension };
1
+ export * from './ResponsiveContainer.tsrx';
@@ -0,0 +1,171 @@
1
+ import type { OctaneNode } from 'octane';
2
+ import {
3
+ createContext,
4
+ useCallback,
5
+ useContext,
6
+ useEffect,
7
+ useImperativeHandle,
8
+ useMemo,
9
+ useRef,
10
+ useState,
11
+ } from 'octane';
12
+ import { clsx } from 'clsx';
13
+ import throttle from 'es-toolkit/compat/throttle';
14
+ import { isNumber, noop } from '../util/DataUtils';
15
+ import {
16
+ calculateChartDimensions,
17
+ defaultResponsiveContainerProps,
18
+ getDefaultWidthAndHeight,
19
+ getInnerDivStyle,
20
+ } from './responsiveContainerUtils';
21
+ import { isPositiveNumber } from '../util/isWellBehavedNumber';
22
+
23
+ export interface ResponsiveContainerDimensions {
24
+ width: number;
25
+ height: number;
26
+ }
27
+
28
+ export interface Props {
29
+ aspect?: number;
30
+ width?: `${number}%` | number;
31
+ height?: `${number}%` | number;
32
+ minWidth?: string | number;
33
+ minHeight?: string | number;
34
+ initialDimension?: ResponsiveContainerDimensions;
35
+ maxHeight?: number;
36
+ children: OctaneNode;
37
+ debounce?: number;
38
+ id?: string | number;
39
+ className?: string | number;
40
+ style?: React.CSSProperties;
41
+ onResize?: (width: number, height: number) => void;
42
+ ref?: React.Ref<HTMLDivElement>;
43
+ [key: string]: any;
44
+ }
45
+
46
+ const initialDimension = defaultResponsiveContainerProps.initialDimension;
47
+ const ResponsiveContainerContext = createContext<ResponsiveContainerDimensions>(initialDimension);
48
+
49
+ export const ResponsiveContainerContextProviderInternal = ResponsiveContainerContext.Provider;
50
+ export const useResponsiveContainerContext = () => useContext(ResponsiveContainerContext);
51
+ export { initialDimension as defaultResponsiveContainerDimension };
52
+
53
+ function ResponsiveContainerContextProvider({
54
+ children,
55
+ width,
56
+ height,
57
+ }: {
58
+ children: OctaneNode;
59
+ width: number | undefined;
60
+ height: number | undefined;
61
+ }) {
62
+ const size = useMemo(() => ({ width, height }), [width, height]);
63
+ if (!isPositiveNumber(size.width) || !isPositiveNumber(size.height)) {
64
+ return null;
65
+ }
66
+ return <ResponsiveContainerContext
67
+ value={size as ResponsiveContainerDimensions}
68
+ >{children}</ResponsiveContainerContext>;
69
+ }
70
+
71
+ function SizeDetectorContainer(props: Props) @{
72
+ const {
73
+ aspect,
74
+ initialDimension: initial = initialDimension,
75
+ width,
76
+ height,
77
+ minWidth = 0,
78
+ minHeight,
79
+ maxHeight,
80
+ children,
81
+ debounce = 0,
82
+ id,
83
+ className,
84
+ onResize,
85
+ style = {},
86
+ ref,
87
+ ...others
88
+ } = props;
89
+ const containerRef = useRef<HTMLDivElement | null>(null);
90
+ const onResizeRef = useRef(onResize);
91
+ onResizeRef.current = onResize;
92
+ useImperativeHandle(ref, () => containerRef.current, []);
93
+ const [sizes, setSizes] = useState({
94
+ containerWidth: initial.width,
95
+ containerHeight: initial.height,
96
+ });
97
+ const setContainerSize = useCallback((newWidth: number, newHeight: number) => {
98
+ const containerWidth = Math.round(newWidth);
99
+ const containerHeight = Math.round(newHeight);
100
+ setSizes(
101
+ (previous) => previous.containerWidth === containerWidth &&
102
+ previous.containerHeight === containerHeight
103
+ ? previous
104
+ : { containerWidth, containerHeight },
105
+ );
106
+ }, []);
107
+ useEffect(() => {
108
+ if (!containerRef.current || typeof ResizeObserver === 'undefined') {
109
+ return noop;
110
+ }
111
+ const handleResize = (entries: ResizeObserverEntry[]) => {
112
+ const entry = entries[0];
113
+ if (!entry) return;
114
+ setContainerSize(entry.contentRect.width, entry.contentRect.height);
115
+ onResizeRef.current?.(entry.contentRect.width, entry.contentRect.height);
116
+ };
117
+ const callback =
118
+ debounce > 0
119
+ ? throttle(handleResize, debounce, { trailing: true, leading: false })
120
+ : handleResize;
121
+ const observer = new ResizeObserver(callback);
122
+ const rect = containerRef.current.getBoundingClientRect();
123
+ setContainerSize(rect.width, rect.height);
124
+ observer.observe(containerRef.current);
125
+ return () => {
126
+ if ('cancel' in callback) callback.cancel();
127
+ observer.disconnect();
128
+ };
129
+ }, [setContainerSize, debounce]);
130
+ const calculated = calculateChartDimensions(sizes.containerWidth, sizes.containerHeight, {
131
+ width,
132
+ height,
133
+ aspect,
134
+ maxHeight,
135
+ });
136
+ const outerProps: any = Object.assign({}, others, {
137
+ id: id ? `${id}` : undefined,
138
+ className: clsx('recharts-responsive-container', className),
139
+ style: { ...style, width, height, minWidth, minHeight, maxHeight },
140
+ ref: containerRef,
141
+ });
142
+ <div {...outerProps}>
143
+ <div style={getInnerDivStyle({ width, height })}>
144
+ <ResponsiveContainerContextProvider
145
+ width={calculated.calculatedWidth}
146
+ height={calculated.calculatedHeight}
147
+ >{children}</ResponsiveContainerContextProvider>
148
+ </div>
149
+ </div>
150
+ }
151
+
152
+ export function ResponsiveContainer(props: Props) {
153
+ const parent = useResponsiveContainerContext();
154
+ if (isPositiveNumber(parent.width) && isPositiveNumber(parent.height)) {
155
+ return props.children;
156
+ }
157
+ const defaults = getDefaultWidthAndHeight(props);
158
+ const calculated = calculateChartDimensions(undefined, undefined, {
159
+ width: defaults.width,
160
+ height: defaults.height,
161
+ aspect: props.aspect,
162
+ maxHeight: props.maxHeight,
163
+ });
164
+ if (isNumber(calculated.calculatedWidth) && isNumber(calculated.calculatedHeight)) {
165
+ return <ResponsiveContainerContextProvider
166
+ width={calculated.calculatedWidth}
167
+ height={calculated.calculatedHeight}
168
+ >{props.children}</ResponsiveContainerContextProvider>;
169
+ }
170
+ return <SizeDetectorContainer {...props} width={defaults.width} height={defaults.height} />;
171
+ }
@@ -0,0 +1,81 @@
1
+ import * as React from 'octane';
2
+ import { CSSProperties, ReactNode } from 'octane';
3
+ import { Percent, Size } from '../util/types';
4
+ export interface Props extends Omit<
5
+ React.HTMLAttributes<HTMLDivElement>,
6
+ 'id' | 'className' | 'style' | 'onResize'
7
+ > {
8
+ /**
9
+ * width / height. If specified, the height will be calculated by width / aspect.
10
+ */
11
+ aspect?: number;
12
+ /**
13
+ * The width of chart container.
14
+ * Can be a number or a percent string like "100%".
15
+ * @default '100%'
16
+ */
17
+ width?: Percent | number;
18
+ /**
19
+ * The height of chart container.
20
+ * Can be a number or a percent string like "100%".
21
+ * @default '100%'
22
+ */
23
+ height?: Percent | number;
24
+ /**
25
+ * The minimum width of the container.
26
+ * @default 0
27
+ */
28
+ minWidth?: string | number;
29
+ /**
30
+ * The minimum height of the container.
31
+ */
32
+ minHeight?: string | number;
33
+ /**
34
+ * The initial width and height of the container.
35
+ * @default {"width":-1,"height":-1}
36
+ */
37
+ initialDimension?: {
38
+ width: number;
39
+ height: number;
40
+ };
41
+ /** The maximum height of the container. It can be a number. */
42
+ maxHeight?: number;
43
+ /**
44
+ * The content of the container.
45
+ * It can contain multiple charts, and then they will all share the same dimensions.
46
+ */
47
+ children: ReactNode;
48
+ /**
49
+ * If specified a positive number, debounced function will be used to handle the resize event.
50
+ * @default 0
51
+ */
52
+ debounce?: number;
53
+ /**
54
+ * Unique identifier of this component.
55
+ * Used as an HTML attribute `id`.
56
+ */
57
+ id?: string | number;
58
+ /** The HTML element's class name */
59
+ className?: string | number;
60
+ /** The style of the container. */
61
+ style?: CSSProperties;
62
+ /**
63
+ * If specified provides a callback providing the updated chart width and height values.
64
+ */
65
+ onResize?: (width: number, height: number) => void;
66
+ }
67
+ export declare const useResponsiveContainerContext: () => Size;
68
+ /**
69
+ * The `ResponsiveContainer` component is a container that adjusts its width and height based on the size of its parent element.
70
+ * It is used to create responsive charts that adapt to different screen sizes.
71
+ *
72
+ * This component uses the {@link https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver ResizeObserver} API to monitor changes to the size of its parent element.
73
+ * If you need to support older browsers that do not support this API, you may need to include a polyfill.
74
+ *
75
+ * @see {@link https://recharts.github.io/en-US/guide/sizes/ Chart size guide}
76
+ *
77
+ * @provides ResponsiveContainerContext
78
+ */
79
+ export declare const ResponsiveContainer: React.ForwardRefExoticComponent<
80
+ Props & React.RefAttributes<HTMLDivElement>
81
+ >;
@@ -0,0 +1,425 @@
1
+ import * as React from 'octane';
2
+ import { CSSProperties, ReactElement, ReactNode, useEffect } from 'octane';
3
+ import { createPortal } from 'octane';
4
+ import {
5
+ DefaultTooltipContent,
6
+ NameType,
7
+ Payload,
8
+ Props as DefaultTooltipContentProps,
9
+ TooltipItemSorter,
10
+ ValueType,
11
+ } from './DefaultTooltipContent';
12
+ import { TooltipBoundingBox } from './TooltipBoundingBox';
13
+
14
+ import { getUniqPayload, UniqueOption } from '../util/payload/getUniqPayload';
15
+ import { AllowInDimension, AnimationDuration, EasingInput, Coordinate } from '../util/types';
16
+ import { useViewBox } from '../context/chartLayoutContext';
17
+ import { useAccessibilityLayer } from '../context/accessibilityContext';
18
+ import { useElementOffset } from '../util/useElementOffset';
19
+ import { Cursor, CursorDefinition } from './Cursor';
20
+ import {
21
+ selectActiveCoordinate,
22
+ selectActiveLabel,
23
+ selectIsTooltipActive,
24
+ selectTooltipPayload,
25
+ } from '../state/selectors/selectors';
26
+ import { useTooltipPortal } from '../context/tooltipPortalContext';
27
+ import type { TooltipTrigger } from '../chart/types';
28
+ import { useAppDispatch, useAppSelector } from '../state/hooks';
29
+ import {
30
+ setTooltipSettingsState,
31
+ TooltipIndex,
32
+ TooltipPayload,
33
+ TooltipPayloadEntry,
34
+ } from '../state/tooltipSlice';
35
+ import { AxisId } from '../state/cartesianAxisSlice';
36
+ import { useTooltipChartSynchronisation } from '../synchronisation/useChartSynchronisation';
37
+ import { useTooltipEventType } from '../state/selectors/selectTooltipEventType';
38
+ import { resolveDefaultProps } from '../util/resolveDefaultProps';
39
+
40
+ export type ContentType<TValue extends ValueType = ValueType, TName extends NameType = NameType> =
41
+ ReactElement | ((props: TooltipContentProps<TValue, TName>) => ReactNode);
42
+
43
+ function defaultUniqBy(entry: Payload<ValueType, NameType>) {
44
+ return entry.dataKey;
45
+ }
46
+
47
+ export type TooltipContentProps<
48
+ TValue extends ValueType = ValueType,
49
+ TName extends NameType = NameType,
50
+ > =
51
+ TooltipProps<TValue, TName> & {
52
+ label?: string | number;
53
+ payload: TooltipPayload;
54
+ coordinate: Coordinate | undefined;
55
+ active: boolean;
56
+ accessibilityLayer: boolean;
57
+ activeIndex: TooltipIndex | undefined;
58
+ };
59
+
60
+ function renderContent<TValue extends ValueType, TName extends NameType>(
61
+ content: ContentType<TValue, TName> | undefined,
62
+ props: TooltipContentProps,
63
+ ): ReactNode {
64
+ if (React.isValidElement(content)) {
65
+ return React.cloneElement(content, props);
66
+ }
67
+ if (typeof content === 'function') {
68
+ return React.createElement(content as any, props);
69
+ }
70
+
71
+ return <DefaultTooltipContent {...props} />;
72
+ }
73
+
74
+ type PropertiesReadFromContext =
75
+ 'viewBox' | 'active' | 'payload' | 'coordinate' | 'label' | 'accessibilityLayer';
76
+
77
+ export type TooltipProps<TValue extends ValueType = ValueType, TName extends NameType = NameType> =
78
+ Omit<DefaultTooltipContentProps<TValue, TName>, PropertiesReadFromContext> & {
79
+ /**
80
+ * If true, then Tooltip is always displayed, once an activeIndex is set by mouse over, or programmatically.
81
+ * If false, then Tooltip is never displayed.
82
+ * If undefined, Recharts will control when the Tooltip displays. This includes mouse and keyboard controls.
83
+ */
84
+ active?: boolean;
85
+ /**
86
+ * This option allows the tooltip to extend beyond the viewBox of the chart itself.
87
+ * @defaultValue {"x":false,"y":false}
88
+ */
89
+ allowEscapeViewBox?: AllowInDimension;
90
+ /**
91
+ * Specifies the duration of animation, the unit of this option is ms.
92
+ * @defaultValue 400
93
+ */
94
+ animationDuration?: AnimationDuration;
95
+ /**
96
+ * The type of easing function.
97
+ * @defaultValue ease
98
+ */
99
+ animationEasing?: EasingInput;
100
+ /**
101
+ * Tooltip always attaches itself to the "Tooltip" axis. Which axis is it? Depends on the layout:
102
+ * - horizontal layout -> X axis
103
+ * - vertical layout -> Y axis
104
+ * - radial layout -> radial axis
105
+ * - centric layout -> angle axis
106
+ *
107
+ * Tooltip will use the default axis for the layout, unless you specify an axisId.
108
+ *
109
+ * @defaultValue 0
110
+ */
111
+ axisId?: AxisId;
112
+ /**
113
+ * Renders the content of the tooltip.
114
+ *
115
+ * This should return HTML elements, not SVG elements.
116
+ *
117
+ * - If not set, the {@link DefaultTooltipContent} component is used.
118
+ * - If set to a React element, this element will be cloned and extra props will be passed in.
119
+ * - If set to a function, the function will be called and should return HTML elements.
120
+ *
121
+ * @see {@link https://recharts.github.io/en-US/examples/CustomContentOfTooltip/ Example with custom content}
122
+ */
123
+ content?: ContentType<TValue, TName>;
124
+ /**
125
+ * The style of tooltip content which is a dom element.
126
+ * @defaultValue {}
127
+ */
128
+ contentStyle?: CSSProperties;
129
+ /**
130
+ * If set false, no cursor will be drawn when tooltip is active.
131
+ * If set a object, the option is the configuration of cursor.
132
+ * If set a React element, the option is the custom react element of drawing cursor.
133
+ * @defaultValue true
134
+ */
135
+ cursor?: CursorDefinition;
136
+ defaultIndex?: number | TooltipIndex;
137
+ /**
138
+ * When an item of the payload has value null or undefined, this item won't be displayed.
139
+ * @defaultValue true
140
+ */
141
+ filterNull?: boolean;
142
+ /**
143
+ * Function to customize the value in the tooltip.
144
+ * If you return an array, the first entry will be the formatted "value", and the second entry will be the formatted "name"
145
+ */
146
+ formatter?: (value: TValue, name: TName, item: TooltipPayloadEntry, index: number, payload: TooltipPayload) => | ReactNode
147
+ | [ReactNode, ReactNode];
148
+ /**
149
+ * If true, the tooltip will display information about hidden series.
150
+ * Defaults to false.
151
+ * Interacting with the hide property of Area, Bar, Line, Scatter.
152
+ *
153
+ * @defaultValue false
154
+ */
155
+ includeHidden?: boolean | undefined;
156
+ /**
157
+ * If set false, animation of tooltip will be disabled.
158
+ * If set "auto", the animation will be disabled in SSR and will respect the user's prefers-reduced-motion system preference for accessibility.
159
+ * @defaultValue auto
160
+ */
161
+ isAnimationActive?: boolean | 'auto';
162
+ /**
163
+ * Sorts tooltip items.
164
+ * Defaults to 'name' which means it sorts alphabetically by graphical item `name` property.
165
+ * @defaultValue name
166
+ */
167
+ itemSorter?: TooltipItemSorter;
168
+ /**
169
+ * The style of default tooltip content item which is a li element.
170
+ * @defaultValue {}
171
+ */
172
+ itemStyle?: CSSProperties;
173
+ /**
174
+ * The formatter function of label in tooltip.
175
+ */
176
+ labelFormatter?: (label: any, payload: TooltipPayload) => ReactNode;
177
+ /**
178
+ * The style of default tooltip label which is a p element.
179
+ * @defaultValue {}
180
+ */
181
+ labelStyle?: CSSProperties;
182
+ /**
183
+ * The offset size between the position of tooltip and the mouse cursor position.
184
+ * When a number is provided, the same offset is applied to both x and y axes.
185
+ *
186
+ * When a Coordinate object is provided, you can specify different offsets for each axis (x and y as numbers)
187
+ * @defaultValue 10
188
+ */
189
+ offset?: number | Coordinate;
190
+ payloadUniqBy?: UniqueOption<TooltipPayloadEntry>;
191
+ /**
192
+ * If portal is defined, then Tooltip will use this element as a target
193
+ * for rendering using React Portal: https://react.dev/reference/react-dom/createPortal
194
+ *
195
+ * If this is undefined then Tooltip renders inside the recharts-wrapper element.
196
+ */
197
+ portal?: HTMLElement | null;
198
+ /**
199
+ * If this field is set, the tooltip will be displayed at the specified position
200
+ * regardless of the mouse position.
201
+ *
202
+ * You can set a single field (x or y) and let the other field be calculated automatically based
203
+ * on the mouse position.
204
+ */
205
+ position?: Partial<Coordinate>;
206
+ /**
207
+ * @defaultValue {"x":false,"y":false}
208
+ */
209
+ reverseDirection?: AllowInDimension;
210
+ /**
211
+ * The separator between name and value.
212
+ * @defaultValue ' : '
213
+ */
214
+ separator?: string;
215
+ /**
216
+ * Defines whether the tooltip is reacting to the current data point,
217
+ * or to all data points at the current axis coordinate.
218
+ *
219
+ * - `true`: tooltip will appear on top of all bars on an axis tick.
220
+ * - `false`: tooltip will appear on individual bars.
221
+ *
222
+ * Different chart types allow different modes, and have different defaults.
223
+ *
224
+ * @see {@link https://github.com/recharts/recharts/wiki/Tooltip-event-type-and-shared-prop Tooltip event type and shared prop wiki page}
225
+ */
226
+ shared?: boolean;
227
+ /**
228
+ * If `hover` then the Tooltip shows on mouse enter and hides on mouse leave.
229
+ *
230
+ * If `click` then the Tooltip shows after clicking and stays active.
231
+ *
232
+ * @defaultValue hover
233
+ */
234
+ trigger?: TooltipTrigger;
235
+ /**
236
+ * @defaultValue false
237
+ */
238
+ useTranslate3d?: boolean;
239
+ /**
240
+ * CSS styles to be applied to the wrapper `div` element.
241
+ */
242
+ wrapperStyle?: CSSProperties;
243
+ };
244
+
245
+ const emptyPayload: TooltipPayload = [];
246
+
247
+ export const defaultTooltipProps = {
248
+ allowEscapeViewBox: { x: false, y: false },
249
+ animationDuration: 400,
250
+ animationEasing: 'ease',
251
+ axisId: 0,
252
+ contentStyle: {},
253
+ cursor: true,
254
+ filterNull: true,
255
+ includeHidden: false,
256
+ isAnimationActive: 'auto',
257
+ itemSorter: 'name',
258
+ itemStyle: {},
259
+ labelStyle: {},
260
+ offset: 10,
261
+ reverseDirection: { x: false, y: false },
262
+ separator: ' : ',
263
+ trigger: 'hover',
264
+ useTranslate3d: false,
265
+ wrapperStyle: {},
266
+ } as const satisfies Partial<TooltipProps<any, any>>;
267
+
268
+ /**
269
+ * The Tooltip component displays a floating box with data values when hovering over or clicking on chart elements.
270
+ *
271
+ * It can be configured to show information for individual data points or for all points at a specific axis coordinate.
272
+ * The appearance and content of the tooltip can be customized via props.
273
+ *
274
+ * @see {@link https://github.com/recharts/recharts/wiki/Tooltip-event-type-and-shared-prop Tooltip event type and shared prop wiki page}
275
+ * @see {@link https://recharts.github.io/en-US/guide/activeIndex/ Active index replacement when migrating from Recharts v2 to v3}
276
+ *
277
+ * @consumes CartesianChartContext
278
+ * @consumes PolarChartContext
279
+ * @consumes TooltipEntrySettings
280
+ */
281
+ export function Tooltip(outsideProps: TooltipProps<ValueType, NameType>) {
282
+ const props = resolveDefaultProps(outsideProps, defaultTooltipProps);
283
+ const {
284
+ active: activeFromProps,
285
+ allowEscapeViewBox,
286
+ animationDuration,
287
+ animationEasing,
288
+ content,
289
+ filterNull,
290
+ isAnimationActive,
291
+ offset,
292
+ payloadUniqBy,
293
+ position,
294
+ reverseDirection,
295
+ useTranslate3d,
296
+ wrapperStyle,
297
+ cursor,
298
+ shared,
299
+ trigger,
300
+ defaultIndex,
301
+ portal: portalFromProps,
302
+ axisId,
303
+ } = props;
304
+ const dispatch = useAppDispatch();
305
+ const defaultIndexAsString: string | null | undefined =
306
+ typeof defaultIndex === 'number' ? String(defaultIndex) : defaultIndex;
307
+
308
+ useEffect(() => {
309
+ dispatch(
310
+ setTooltipSettingsState({
311
+ shared,
312
+ trigger,
313
+ axisId,
314
+ active: activeFromProps,
315
+ defaultIndex: defaultIndexAsString,
316
+ }),
317
+ );
318
+ }, [dispatch, shared, trigger, axisId, activeFromProps, defaultIndexAsString]);
319
+
320
+ const viewBox = useViewBox();
321
+ const accessibilityLayer = useAccessibilityLayer();
322
+ const tooltipEventType = useTooltipEventType(shared);
323
+
324
+ const { activeIndex, isActive } =
325
+ useAppSelector(
326
+ (state) => selectIsTooltipActive(state, tooltipEventType, trigger, defaultIndexAsString),
327
+ ) ??
328
+ {};
329
+
330
+ const payloadFromRedux = useAppSelector(
331
+ (state) => selectTooltipPayload(state, tooltipEventType, trigger, defaultIndexAsString),
332
+ );
333
+
334
+ const labelFromRedux = useAppSelector(
335
+ (state) => selectActiveLabel(state, tooltipEventType, trigger, defaultIndexAsString),
336
+ );
337
+
338
+ const coordinate: Coordinate | undefined = useAppSelector(
339
+ (state) => selectActiveCoordinate(state, tooltipEventType, trigger, defaultIndexAsString),
340
+ );
341
+ const payload: TooltipPayload | undefined = payloadFromRedux;
342
+ const tooltipPortalFromContext = useTooltipPortal();
343
+ /*
344
+ * The user can set `active=true` on the Tooltip in which case the Tooltip will stay always active,
345
+ * or `active=false` in which case the Tooltip never shows.
346
+ *
347
+ * If the `active` prop is not defined then it will show and hide based on mouse or keyboard activity.
348
+ */
349
+ const finalIsActive: boolean = activeFromProps ?? isActive ?? false;
350
+ const [lastBoundingBox, updateBoundingBox] = useElementOffset([payload, finalIsActive]);
351
+ const finalLabel =
352
+ tooltipEventType === 'axis' ? labelFromRedux : undefined;
353
+
354
+ useTooltipChartSynchronisation(
355
+ tooltipEventType,
356
+ trigger,
357
+ coordinate,
358
+ finalLabel,
359
+ activeIndex,
360
+ finalIsActive,
361
+ );
362
+
363
+ const tooltipPortal = portalFromProps ?? tooltipPortalFromContext;
364
+ if (tooltipPortal == null || viewBox == null || tooltipEventType == null) {
365
+ return null;
366
+ }
367
+
368
+ let finalPayload: TooltipPayload = payload ?? emptyPayload;
369
+ if (!finalIsActive) {
370
+ finalPayload = emptyPayload;
371
+ }
372
+
373
+ if (filterNull && finalPayload.length) {
374
+ finalPayload = getUniqPayload(
375
+ finalPayload.filter(
376
+ (entry) => entry.value != null && (entry.hide !== true || props.includeHidden),
377
+ ),
378
+ payloadUniqBy,
379
+ defaultUniqBy,
380
+ );
381
+ }
382
+ const hasPayload = finalPayload.length > 0;
383
+
384
+ const tooltipContentProps: TooltipContentProps = {
385
+ ...props,
386
+ payload: finalPayload,
387
+ label: finalLabel,
388
+ active: finalIsActive,
389
+ activeIndex,
390
+ coordinate,
391
+ accessibilityLayer,
392
+ };
393
+
394
+ const tooltipElement = <TooltipBoundingBox
395
+ allowEscapeViewBox={allowEscapeViewBox}
396
+ animationDuration={animationDuration}
397
+ animationEasing={animationEasing}
398
+ isAnimationActive={isAnimationActive}
399
+ active={finalIsActive}
400
+ coordinate={coordinate}
401
+ hasPayload={hasPayload}
402
+ offset={offset}
403
+ position={position}
404
+ reverseDirection={reverseDirection}
405
+ useTranslate3d={useTranslate3d}
406
+ viewBox={viewBox}
407
+ wrapperStyle={wrapperStyle}
408
+ lastBoundingBox={lastBoundingBox}
409
+ innerRef={updateBoundingBox}
410
+ hasPortalFromProps={Boolean(portalFromProps)}
411
+ >{renderContent(content, tooltipContentProps)}</TooltipBoundingBox>;
412
+
413
+ return <>
414
+ {/* Tooltip the HTML element renders through a React portal so that it escapes clipping, and it renders on top of everything else */}
415
+ {createPortal(tooltipElement, tooltipPortal)}
416
+ {finalIsActive &&
417
+ <Cursor
418
+ cursor={cursor}
419
+ tooltipEventType={tooltipEventType}
420
+ coordinate={coordinate}
421
+ payload={finalPayload}
422
+ index={activeIndex}
423
+ />}
424
+ </>;
425
+ }