@solidports/recharts 0.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.
Files changed (306) hide show
  1. package/LICENSE +22 -0
  2. package/NOTICE +19 -0
  3. package/README.md +102 -0
  4. package/dist/dev.js +28564 -0
  5. package/dist/index.d.ts +7859 -0
  6. package/dist/index.js +28546 -0
  7. package/package.json +98 -0
  8. package/src/animation/AnimatedItems.tsx +183 -0
  9. package/src/animation/AnimationController.ts +33 -0
  10. package/src/animation/AnimationControllerImpl.ts +36 -0
  11. package/src/animation/AnimationHandle.ts +307 -0
  12. package/src/animation/CSSTransitionAnimate.tsx +170 -0
  13. package/src/animation/JavascriptAnimate.tsx +119 -0
  14. package/src/animation/easing.ts +221 -0
  15. package/src/animation/matchBy.ts +164 -0
  16. package/src/animation/timeoutController.ts +70 -0
  17. package/src/animation/useAnimationController.tsx +34 -0
  18. package/src/animation/useAnimationStartSnapshot.ts +118 -0
  19. package/src/animation/util.ts +41 -0
  20. package/src/cartesian/Area.tsx +915 -0
  21. package/src/cartesian/AreaRevealShape.tsx +190 -0
  22. package/src/cartesian/Bar.tsx +1369 -0
  23. package/src/cartesian/BarStack.tsx +152 -0
  24. package/src/cartesian/Brush.tsx +951 -0
  25. package/src/cartesian/CartesianAxis.tsx +722 -0
  26. package/src/cartesian/CartesianGrid.tsx +711 -0
  27. package/src/cartesian/ErrorBar.tsx +361 -0
  28. package/src/cartesian/Funnel.tsx +803 -0
  29. package/src/cartesian/GraphicalItemClipPath.tsx +67 -0
  30. package/src/cartesian/Line.tsx +863 -0
  31. package/src/cartesian/LineDrawShape.tsx +89 -0
  32. package/src/cartesian/ReferenceArea.tsx +331 -0
  33. package/src/cartesian/ReferenceDot.tsx +304 -0
  34. package/src/cartesian/ReferenceLine.tsx +474 -0
  35. package/src/cartesian/Scatter.tsx +888 -0
  36. package/src/cartesian/XAxis.tsx +433 -0
  37. package/src/cartesian/YAxis.tsx +443 -0
  38. package/src/cartesian/ZAxis.tsx +155 -0
  39. package/src/cartesian/cartesianPositionToCSSTranslate.tsx +29 -0
  40. package/src/cartesian/cartesianViewBoxToTrapezoid.tsx +21 -0
  41. package/src/cartesian/getCartesianPosition.tsx +267 -0
  42. package/src/cartesian/getEquidistantTicks.ts +144 -0
  43. package/src/cartesian/getTicks.ts +225 -0
  44. package/src/cartesian/isOutsidePosition.ts +15 -0
  45. package/src/cartesian/useAnimatedLineLength.ts +54 -0
  46. package/src/chart/AreaChart.tsx +29 -0
  47. package/src/chart/BarChart.tsx +29 -0
  48. package/src/chart/CartesianChart.tsx +131 -0
  49. package/src/chart/CategoricalChart.tsx +94 -0
  50. package/src/chart/ComposedChart.tsx +29 -0
  51. package/src/chart/FunnelChart.tsx +29 -0
  52. package/src/chart/LineChart.tsx +29 -0
  53. package/src/chart/PieChart.tsx +50 -0
  54. package/src/chart/PolarChart.tsx +164 -0
  55. package/src/chart/RadarChart.tsx +70 -0
  56. package/src/chart/RadialBarChart.tsx +46 -0
  57. package/src/chart/RechartsWrapper.tsx +551 -0
  58. package/src/chart/Sankey.tsx +1534 -0
  59. package/src/chart/ScatterChart.tsx +29 -0
  60. package/src/chart/SunburstChart.tsx +504 -0
  61. package/src/chart/Treemap.tsx +1223 -0
  62. package/src/chart/createInitialRootProps.ts +24 -0
  63. package/src/chart/types.ts +53 -0
  64. package/src/component/ActivePoints.tsx +144 -0
  65. package/src/component/Cell.tsx +37 -0
  66. package/src/component/Cursor.tsx +185 -0
  67. package/src/component/Customized.tsx +50 -0
  68. package/src/component/DefaultLegendContent.tsx +348 -0
  69. package/src/component/DefaultTooltipContent.tsx +224 -0
  70. package/src/component/Dots.tsx +157 -0
  71. package/src/component/Label.tsx +636 -0
  72. package/src/component/LabelList.tsx +375 -0
  73. package/src/component/Legend.tsx +512 -0
  74. package/src/component/ResponsiveContainer.tsx +348 -0
  75. package/src/component/Text.tsx +541 -0
  76. package/src/component/Tooltip.tsx +470 -0
  77. package/src/component/TooltipBoundingBox.tsx +146 -0
  78. package/src/component/responsiveContainerUtils.ts +134 -0
  79. package/src/container/ClipPathProvider.tsx +51 -0
  80. package/src/container/Layer.tsx +38 -0
  81. package/src/container/RootSurface.tsx +120 -0
  82. package/src/container/Surface.tsx +61 -0
  83. package/src/context/CellsContext.tsx +54 -0
  84. package/src/context/ErrorBarContext.tsx +146 -0
  85. package/src/context/GraphicalItemChildrenScope.tsx +18 -0
  86. package/src/context/PanoramaContext.tsx +9 -0
  87. package/src/context/RegisterGraphicalItemId.tsx +30 -0
  88. package/src/context/accessibilityContext.tsx +6 -0
  89. package/src/context/brushUpdateContext.tsx +9 -0
  90. package/src/context/chartDataContext.tsx +97 -0
  91. package/src/context/chartLayoutContext.tsx +201 -0
  92. package/src/context/legendPayloadContext.tsx +20 -0
  93. package/src/context/legendPortalContext.tsx +12 -0
  94. package/src/context/tooltipContext.tsx +89 -0
  95. package/src/context/tooltipPortalContext.tsx +12 -0
  96. package/src/context/useTooltipAxis.ts +22 -0
  97. package/src/hooks.ts +476 -0
  98. package/src/index.ts +280 -0
  99. package/src/polar/Pie.tsx +1360 -0
  100. package/src/polar/PolarAngleAxis.tsx +616 -0
  101. package/src/polar/PolarGrid.tsx +312 -0
  102. package/src/polar/PolarRadiusAxis.tsx +547 -0
  103. package/src/polar/Radar.tsx +734 -0
  104. package/src/polar/RadialBar.tsx +917 -0
  105. package/src/polar/defaultPolarAngleAxisProps.tsx +27 -0
  106. package/src/polar/defaultPolarRadiusAxisProps.tsx +25 -0
  107. package/src/shape/Cross.tsx +89 -0
  108. package/src/shape/Curve.tsx +343 -0
  109. package/src/shape/Dot.tsx +70 -0
  110. package/src/shape/Polygon.tsx +195 -0
  111. package/src/shape/Rectangle.tsx +470 -0
  112. package/src/shape/Sector.tsx +347 -0
  113. package/src/shape/Symbols.tsx +139 -0
  114. package/src/shape/Trapezoid.tsx +280 -0
  115. package/src/state/RechartsStateContext.tsx +12 -0
  116. package/src/state/RechartsStateProvider.tsx +87 -0
  117. package/src/state/RechartsStoreContext.tsx +25 -0
  118. package/src/state/RechartsStoreProvider.tsx +35 -0
  119. package/src/state/ReportChartProps.tsx +40 -0
  120. package/src/state/ReportEventSettings.tsx +30 -0
  121. package/src/state/ReportMainChartProps.tsx +61 -0
  122. package/src/state/ReportPolarOptions.tsx +35 -0
  123. package/src/state/SetGraphicalItem.ts +79 -0
  124. package/src/state/SetLegendPayload.ts +134 -0
  125. package/src/state/SetTooltipEntrySettings.tsx +72 -0
  126. package/src/state/actions.ts +464 -0
  127. package/src/state/brushSlice.ts +13 -0
  128. package/src/state/cartesianAxisSlice.ts +141 -0
  129. package/src/state/chartDataSlice.ts +50 -0
  130. package/src/state/chartState.ts +297 -0
  131. package/src/state/errorBarSlice.ts +29 -0
  132. package/src/state/eventSettingsSlice.ts +8 -0
  133. package/src/state/events.ts +76 -0
  134. package/src/state/externalEventsMiddleware.ts +255 -0
  135. package/src/state/graphicalItemsSlice.ts +74 -0
  136. package/src/state/hooks/useChartSelectors.tsx +45 -0
  137. package/src/state/keyboardEventsMiddleware.ts +228 -0
  138. package/src/state/layoutSlice.ts +21 -0
  139. package/src/state/legendSlice.ts +57 -0
  140. package/src/state/mouseEventsMiddleware.ts +185 -0
  141. package/src/state/optionsSlice.ts +47 -0
  142. package/src/state/polarAxisSlice.ts +10 -0
  143. package/src/state/polarOptionsSlice.ts +12 -0
  144. package/src/state/rawData.ts +26 -0
  145. package/src/state/referenceElementsSlice.ts +40 -0
  146. package/src/state/renderedTicksSlice.ts +15 -0
  147. package/src/state/rootPropsSlice.ts +47 -0
  148. package/src/state/selectors/areaSelectors.ts +240 -0
  149. package/src/state/selectors/arrayEqualityCheck.ts +29 -0
  150. package/src/state/selectors/axisSelectors.ts +2157 -0
  151. package/src/state/selectors/barSelectors.ts +310 -0
  152. package/src/state/selectors/barStackSelectors.ts +77 -0
  153. package/src/state/selectors/brushSelectors.ts +33 -0
  154. package/src/state/selectors/chartSelector.ts +185 -0
  155. package/src/state/selectors/combiners/combineActiveLabel.ts +16 -0
  156. package/src/state/selectors/combiners/combineActiveTooltipIndex.ts +95 -0
  157. package/src/state/selectors/combiners/combineAllBarPositions.ts +122 -0
  158. package/src/state/selectors/combiners/combineAxisRangeWithReverse.ts +16 -0
  159. package/src/state/selectors/combiners/combineBarPosition.ts +23 -0
  160. package/src/state/selectors/combiners/combineBarSizeList.ts +80 -0
  161. package/src/state/selectors/combiners/combineCheckedDomain.ts +48 -0
  162. package/src/state/selectors/combiners/combineConfiguredScale.ts +111 -0
  163. package/src/state/selectors/combiners/combineCoordinateForDefaultIndex.ts +45 -0
  164. package/src/state/selectors/combiners/combineDisplayedStackedData.ts +50 -0
  165. package/src/state/selectors/combiners/combineInverseScaleFunction.ts +16 -0
  166. package/src/state/selectors/combiners/combineRealScaleType.ts +44 -0
  167. package/src/state/selectors/combiners/combineStackedData.ts +27 -0
  168. package/src/state/selectors/combiners/combineTooltipInteractionState.ts +86 -0
  169. package/src/state/selectors/combiners/combineTooltipPayload.ts +205 -0
  170. package/src/state/selectors/combiners/combineTooltipPayloadConfigurations.ts +58 -0
  171. package/src/state/selectors/containerSelectors.ts +12 -0
  172. package/src/state/selectors/dataSelectors.ts +88 -0
  173. package/src/state/selectors/funnelSelectors.ts +75 -0
  174. package/src/state/selectors/graphicalItemSelectors.ts +30 -0
  175. package/src/state/selectors/legendSelectors.ts +29 -0
  176. package/src/state/selectors/lineSelectors.ts +134 -0
  177. package/src/state/selectors/numberDomainEqualityCheck.ts +14 -0
  178. package/src/state/selectors/pickAxisId.ts +5 -0
  179. package/src/state/selectors/pickAxisType.ts +3 -0
  180. package/src/state/selectors/pieSelectors.ts +97 -0
  181. package/src/state/selectors/polarAxisSelectors.ts +201 -0
  182. package/src/state/selectors/polarGridSelectors.ts +28 -0
  183. package/src/state/selectors/polarScaleSelectors.ts +133 -0
  184. package/src/state/selectors/polarSelectors.ts +219 -0
  185. package/src/state/selectors/radarSelectors.ts +191 -0
  186. package/src/state/selectors/radialBarSelectors.ts +435 -0
  187. package/src/state/selectors/rootPropsSelectors.ts +25 -0
  188. package/src/state/selectors/scatterSelectors.ts +96 -0
  189. package/src/state/selectors/selectActivePropsFromChartPointer.ts +26 -0
  190. package/src/state/selectors/selectAllAxes.ts +17 -0
  191. package/src/state/selectors/selectChartOffset.ts +16 -0
  192. package/src/state/selectors/selectChartOffsetInternal.ts +136 -0
  193. package/src/state/selectors/selectLegendArea.ts +20 -0
  194. package/src/state/selectors/selectPlotArea.ts +22 -0
  195. package/src/state/selectors/selectTooltipAxisId.ts +7 -0
  196. package/src/state/selectors/selectTooltipAxisType.ts +32 -0
  197. package/src/state/selectors/selectTooltipEventType.ts +48 -0
  198. package/src/state/selectors/selectTooltipPayloadSearcher.ts +6 -0
  199. package/src/state/selectors/selectTooltipSettings.ts +39 -0
  200. package/src/state/selectors/selectTooltipState.ts +8 -0
  201. package/src/state/selectors/selectors.ts +271 -0
  202. package/src/state/selectors/tooltipSelectors.ts +578 -0
  203. package/src/state/selectors/touchSelectors.ts +31 -0
  204. package/src/state/store.ts +29 -0
  205. package/src/state/storeIdentity.ts +9 -0
  206. package/src/state/teardownWrite.ts +10 -0
  207. package/src/state/tooltipInteraction.ts +23 -0
  208. package/src/state/tooltipSlice.ts +334 -0
  209. package/src/state/touchEventsMiddleware.ts +214 -0
  210. package/src/state/types/AnimationSettings.ts +20 -0
  211. package/src/state/types/AreaSettings.ts +14 -0
  212. package/src/state/types/BarSettings.ts +15 -0
  213. package/src/state/types/LineSettings.ts +9 -0
  214. package/src/state/types/PieSettings.ts +34 -0
  215. package/src/state/types/RadarSettings.ts +5 -0
  216. package/src/state/types/RadialBarSettings.ts +10 -0
  217. package/src/state/types/ScatterSettings.ts +12 -0
  218. package/src/state/types/StackedGraphicalItem.ts +34 -0
  219. package/src/state/useChartState.ts +17 -0
  220. package/src/state/zIndexSlice.ts +39 -0
  221. package/src/synchronisation/syncSelectors.ts +7 -0
  222. package/src/synchronisation/types.ts +44 -0
  223. package/src/synchronisation/useChartSynchronisation.tsx +404 -0
  224. package/src/theme/RechartsTheme.ts +16 -0
  225. package/src/theme/RechartsThemeContext.ts +19 -0
  226. package/src/theme/darkTheme.ts +13 -0
  227. package/src/theme/graphicalItemIdentity.ts +70 -0
  228. package/src/theme/legacyTheme.ts +17 -0
  229. package/src/theme/lightTheme.ts +13 -0
  230. package/src/types.ts +54 -0
  231. package/src/util/ActiveShapeUtils.tsx +162 -0
  232. package/src/util/BarUtils.tsx +62 -0
  233. package/src/util/BarePortal.tsx +50 -0
  234. package/src/util/CamelCaseSVGAttrs.ts +34 -0
  235. package/src/util/CartesianUtils.ts +48 -0
  236. package/src/util/ChartUtils.ts +802 -0
  237. package/src/util/Constants.ts +42 -0
  238. package/src/util/CssPrefixUtils.ts +20 -0
  239. package/src/util/DOMUtils.ts +129 -0
  240. package/src/util/DataUtils.ts +216 -0
  241. package/src/util/Events.ts +16 -0
  242. package/src/util/FunnelUtils.tsx +15 -0
  243. package/src/util/Global.ts +12 -0
  244. package/src/util/IfOverflow.ts +15 -0
  245. package/src/util/LRUCache.ts +41 -0
  246. package/src/util/LogUtils.ts +22 -0
  247. package/src/util/PolarUtils.ts +132 -0
  248. package/src/util/RadialBarUtils.tsx +24 -0
  249. package/src/util/ReactUtils.ts +95 -0
  250. package/src/util/ReduceCSSCalc.ts +187 -0
  251. package/src/util/ScatterUtils.tsx +52 -0
  252. package/src/util/ShapeElementProps.tsx +87 -0
  253. package/src/util/TickUtils.ts +60 -0
  254. package/src/util/XAxisUtils.ts +48 -0
  255. package/src/util/YAxisUtils.ts +48 -0
  256. package/src/util/axisPropsAreEqual.ts +48 -0
  257. package/src/util/createCartesianCharts.tsx +150 -0
  258. package/src/util/createEventProxy.ts +20 -0
  259. package/src/util/createPolarCharts.tsx +112 -0
  260. package/src/util/cursor/getCursorPoints.ts +46 -0
  261. package/src/util/cursor/getCursorRectangle.ts +28 -0
  262. package/src/util/cursor/getRadialCursorPoints.ts +32 -0
  263. package/src/util/excludeEventProps.ts +171 -0
  264. package/src/util/getActiveCoordinate.ts +213 -0
  265. package/src/util/getAxisTypeBasedOnLayout.ts +21 -0
  266. package/src/util/getClassNameFromUnknown.ts +6 -0
  267. package/src/util/getEveryNth.ts +27 -0
  268. package/src/util/getRadiusAndStrokeWidthFromDot.ts +35 -0
  269. package/src/util/getRelativeCoordinate.ts +80 -0
  270. package/src/util/getSliced.ts +13 -0
  271. package/src/util/hoverDedupe.ts +41 -0
  272. package/src/util/isDomainSpecifiedByUser.ts +219 -0
  273. package/src/util/isWellBehavedNumber.ts +7 -0
  274. package/src/util/pathTotalLength.ts +25 -0
  275. package/src/util/payload/getUniqPayload.ts +28 -0
  276. package/src/util/propsAreEqual.ts +121 -0
  277. package/src/util/resolveDefaultProps.ts +161 -0
  278. package/src/util/round.ts +32 -0
  279. package/src/util/scale/CartesianScaleHelper.ts +72 -0
  280. package/src/util/scale/CustomScaleDefinition.ts +81 -0
  281. package/src/util/scale/RechartsScale.ts +130 -0
  282. package/src/util/scale/createCategoricalInverse.ts +72 -0
  283. package/src/util/scale/getNiceTickValues.ts +311 -0
  284. package/src/util/scale/index.ts +2 -0
  285. package/src/util/scale/util/arithmetic.ts +54 -0
  286. package/src/util/solid-1-compat.ts +310 -0
  287. package/src/util/solidJsxCamelAugment.d.ts +84 -0
  288. package/src/util/stacks/getStackSeriesIdentifier.ts +21 -0
  289. package/src/util/stacks/stackTypes.ts +60 -0
  290. package/src/util/structurallyEqual.ts +31 -0
  291. package/src/util/svgPropertiesAndEvents.ts +53 -0
  292. package/src/util/svgPropertiesNoEvents.ts +571 -0
  293. package/src/util/tooltip/translate.ts +171 -0
  294. package/src/util/typedDataKey.ts +48 -0
  295. package/src/util/types.ts +1560 -0
  296. package/src/util/useAnimationId.ts +31 -0
  297. package/src/util/useElementOffset.ts +110 -0
  298. package/src/util/useId.ts +8 -0
  299. package/src/util/usePrefersReducedMotion.ts +48 -0
  300. package/src/util/useReportScale.ts +24 -0
  301. package/src/util/useUniqueId.ts +30 -0
  302. package/src/zIndex/DefaultZIndexes.ts +84 -0
  303. package/src/zIndex/ZIndexLayer.tsx +121 -0
  304. package/src/zIndex/ZIndexPortal.tsx +79 -0
  305. package/src/zIndex/getZIndexFromUnknown.ts +14 -0
  306. package/src/zIndex/zIndexSelectors.ts +48 -0
@@ -0,0 +1,46 @@
1
+ /* eslint-disable import/no-cycle */
2
+ import type { JSX } from '@solidjs/web';
3
+ import { arrayTooltipSearcher } from "../state/optionsSlice"
4
+ import type { PolarChartProps, TooltipEventType } from "../util/types"
5
+ import { defaultPolarChartProps, PolarChart } from "./PolarChart"
6
+
7
+ import { mergeProps } from '../util/solid-1-compat';
8
+ const allowedTooltipTypes: ReadonlyArray<TooltipEventType> = ["axis", "item"]
9
+
10
+ export const defaultRadialBarChartProps = {
11
+ ...defaultPolarChartProps,
12
+ endAngle: 360,
13
+ layout: "radial",
14
+ startAngle: 0,
15
+ } as const satisfies Partial<PolarChartProps<never>>
16
+
17
+ /**
18
+ * @consumes ResponsiveContainerContext
19
+ * @provides PolarViewBoxContext
20
+ * @provides PolarChartContext
21
+ */
22
+ export function RadialBarChart<DataPointType = unknown>(
23
+ props: PolarChartProps<DataPointType> & { ref?: SVGSVGElement | ((el: SVGSVGElement) => void) },
24
+ ): JSX.Element {
25
+ /* mergeProps preserves the props proxy — see PieChart for the rationale. */
26
+ const propsWithDefaults = mergeProps(defaultRadialBarChartProps, props) as PolarChartProps<
27
+ DataPointType
28
+ > & {
29
+ cx: NonNullable<PolarChartProps["cx"]>
30
+ cy: NonNullable<PolarChartProps["cy"]>
31
+ startAngle: NonNullable<PolarChartProps["startAngle"]>
32
+ endAngle: NonNullable<PolarChartProps["endAngle"]>
33
+ innerRadius: NonNullable<PolarChartProps["innerRadius"]>
34
+ outerRadius: NonNullable<PolarChartProps["outerRadius"]>
35
+ }
36
+ return (
37
+ <PolarChart
38
+ chartName="RadialBarChart"
39
+ defaultTooltipEventType="axis"
40
+ validateTooltipEventTypes={allowedTooltipTypes}
41
+ tooltipPayloadSearcher={arrayTooltipSearcher}
42
+ categoricalChartProps={propsWithDefaults}
43
+ ref={props.ref}
44
+ />
45
+ )
46
+ }
@@ -0,0 +1,551 @@
1
+ /* eslint-disable import/no-cycle */
2
+ import type { JSX } from '@solidjs/web';
3
+ import { createSignal, onCleanup, untrack } from 'solid-js';
4
+ import { clsx } from "clsx"
5
+ import { useChartStore } from "../state/RechartsStoreContext"
6
+ import { useOptionalChartState } from "../state/useChartState"
7
+ import { useSynchronisedEventsFromOtherCharts } from "../synchronisation/useChartSynchronisation"
8
+ import { useReportScale } from "../util/useReportScale"
9
+ import type { ExternalMouseEvents } from "./types"
10
+ import { TooltipPortalContext } from "../context/tooltipPortalContext"
11
+ import { LegendPortalContext } from "../context/legendPortalContext"
12
+ import { ReportChartSize } from "../context/chartLayoutContext"
13
+ import { useResponsiveContainerContext } from "../component/ResponsiveContainer"
14
+ import type { HTMLMousePointer, Percent } from "../util/types"
15
+
16
+ export type RechartsWrapperProps = ExternalMouseEvents & {
17
+ children: JSX.Element
18
+ width: number | Percent | undefined
19
+ height: number | Percent | undefined
20
+ /**
21
+ * If true, then it will listen to container size changes and adapt the SVG chart accordingly.
22
+ * If false, then it renders the chart at the specified width and height and will stay that way
23
+ * even if the container size changes.
24
+ */
25
+ responsive: boolean
26
+ class?: string
27
+ style?: JSX.CSSProperties
28
+ ref?: HTMLDivElement | ((el: HTMLDivElement) => void)
29
+ /**
30
+ * Treemap is special snowflake that handles its own mouse events so
31
+ * here is a flag to disable the dispatching of mouse events from RechartsWrapper.
32
+ * If false, then this disables mouse click and touch event dispatching.
33
+ * Mouse move events are still dispatched because they are needed for tooltip synchronization.
34
+ * @default true
35
+ */
36
+ dispatchTouchEvents?: boolean
37
+ }
38
+
39
+ function EventSynchronizer(): null {
40
+ useSynchronisedEventsFromOtherCharts()
41
+ return null
42
+ }
43
+
44
+ /* Solid does not auto-append `px` to numeric inline style values like React does
45
+ for length properties — `height: 200` lands on the DOM as a unitless string and
46
+ browsers ignore it. Mirror React's behavior on length-typed keys. */
47
+ const PX_KEYS = new Set([
48
+ "width",
49
+ "height",
50
+ "minWidth",
51
+ "minHeight",
52
+ "maxWidth",
53
+ "maxHeight",
54
+ "top",
55
+ "left",
56
+ "right",
57
+ "bottom",
58
+ ])
59
+ function pxifyStyle(style: JSX.CSSProperties | undefined): JSX.CSSProperties | undefined {
60
+ if (style == null) return style
61
+ let mutated = false
62
+ const out: Record<string, string | number> = {}
63
+ for (const k of Object.keys(style)) {
64
+ const v = (style as Record<string, string | number | undefined>)[k]
65
+ if (v == null) continue
66
+ if (PX_KEYS.has(k) && typeof v === "number") {
67
+ out[k] = `${v}px`
68
+ mutated = true
69
+ } else {
70
+ out[k] = v
71
+ }
72
+ }
73
+ return mutated ? (out as JSX.CSSProperties) : style
74
+ }
75
+
76
+ function getNumberOrZero(value: number | string | undefined): number {
77
+ if (typeof value === "number") {
78
+ return value
79
+ }
80
+ if (typeof value === "string") {
81
+ const parsed = parseFloat(value)
82
+ if (!Number.isNaN(parsed)) {
83
+ return parsed
84
+ }
85
+ }
86
+ return 0
87
+ }
88
+
89
+ type WrapperDivProps = {
90
+ width: number | string | undefined
91
+ height: number | string | undefined
92
+ class?: string
93
+ style?: JSX.CSSProperties
94
+ ref?: HTMLDivElement | ((el: HTMLDivElement) => void)
95
+ onClick?: (e: MouseEvent) => void
96
+ onContextMenu?: (e: MouseEvent) => void
97
+ onDblClick?: (e: MouseEvent) => void
98
+ /* `onFocus`/`onBlur` (focus/blur events) do NOT bubble in the DOM. The
99
+ * focusable target is the inner `<svg tabindex=0>`, not this wrapper div —
100
+ * so a focus event on the svg never reaches a div-level `onfocus` listener.
101
+ * Solid binds events 1:1 with the DOM (no React-style synthetic delegation),
102
+ * so we listen to `focusin`/`focusout` instead — those bubble. */
103
+ onFocusIn?: () => void
104
+ onFocusOut?: () => void
105
+ onKeyDown?: (e: KeyboardEvent) => void
106
+ onMouseDown?: (e: MouseEvent) => void
107
+ onMouseEnter?: (e: MouseEvent) => void
108
+ onMouseLeave?: (e: MouseEvent) => void
109
+ onMouseMove?: (e: MouseEvent) => void
110
+ /* React's onMouseEnter/Leave were synthetic and fired on mouseover/mouseout too.
111
+ Solid binds native events 1:1 — mouseenter doesn't fire on fireEvent.mouseOver.
112
+ Bind both pairs so test helpers that fire mouseOver/mouseOut still trigger
113
+ the same dispatch path users get from real-browser pointer entry. */
114
+ onMouseOver?: (e: MouseEvent) => void
115
+ onMouseOut?: (e: MouseEvent) => void
116
+ onMouseUp?: (e: MouseEvent) => void
117
+ onTouchEnd?: (e: TouchEvent) => void
118
+ onTouchMove?: (e: TouchEvent) => void
119
+ onTouchStart?: (e: TouchEvent) => void
120
+ children?: JSX.Element
121
+ }
122
+
123
+ function ResponsiveDiv(props: WrapperDivProps) {
124
+ let observerRef: ResizeObserver | null = null
125
+
126
+ /* eslint-disable solid/reactivity -- props.style.height/width seed signal once at setup; innerRef is a callback ref (not a signal), used correctly with ref={innerRef} */
127
+ const [sizes, setSizes] = createSignal<{
128
+ containerWidth: number
129
+ containerHeight: number
130
+ }>(
131
+ untrack(() => ({
132
+ containerHeight: getNumberOrZero(props.style?.height),
133
+ containerWidth: getNumberOrZero(props.style?.width),
134
+ })),
135
+ )
136
+ /* eslint-enable solid/reactivity */
137
+
138
+ function setContainerSize(newWidth: number, newHeight: number) {
139
+ const roundedWidth = Math.round(newWidth)
140
+ const roundedHeight = Math.round(newHeight)
141
+ const prev = untrack(sizes)
142
+ if (prev.containerWidth === roundedWidth && prev.containerHeight === roundedHeight) {
143
+ return
144
+ }
145
+ setSizes({ containerHeight: roundedHeight, containerWidth: roundedWidth })
146
+ }
147
+
148
+ /* eslint-disable-next-line solid/reactivity -- innerRef is a callback ref assigned via ref={innerRef}; linter false-positive on function-as-ref */
149
+ function innerRef(node: HTMLDivElement) {
150
+ if (typeof props.ref === "function") {
151
+ props.ref(node)
152
+ }
153
+ if (typeof ResizeObserver !== "undefined") {
154
+ const { width: containerWidth, height: containerHeight } = node.getBoundingClientRect()
155
+ setContainerSize(containerWidth, containerHeight)
156
+ const callback = (entries: ResizeObserverEntry[]) => {
157
+ const entry = entries[0]
158
+ if (entry == null) {
159
+ return
160
+ }
161
+ const { width, height } = entry.contentRect
162
+ setContainerSize(width, height)
163
+ }
164
+ const observer = new ResizeObserver(callback)
165
+ observer.observe(node)
166
+ observerRef = observer
167
+ }
168
+ }
169
+
170
+ onCleanup(() => {
171
+ if (observerRef != null) {
172
+ observerRef.disconnect()
173
+ }
174
+ })
175
+
176
+ /* eslint-disable solid/reactivity -- innerRef is a callback ref; ref={fn} is the correct Solid pattern */
177
+ return (
178
+ <>
179
+ <ReportChartSize width={sizes().containerWidth} height={sizes().containerHeight} />
180
+ <div
181
+ ref={innerRef}
182
+ class={props.class}
183
+ style={pxifyStyle(props.style)}
184
+ onClick={(e) => props.onClick?.(e)}
185
+ onContextMenu={(e) => props.onContextMenu?.(e)}
186
+ onDblClick={(e) => props.onDblClick?.(e)}
187
+ onFocusIn={() => props.onFocusIn?.()}
188
+ onFocusOut={() => props.onFocusOut?.()}
189
+ onKeyDown={(e) => props.onKeyDown?.(e)}
190
+ onMouseDown={(e) => props.onMouseDown?.(e)}
191
+ onMouseEnter={(e) => props.onMouseEnter?.(e)}
192
+ onMouseLeave={(e) => props.onMouseLeave?.(e)}
193
+ onMouseMove={(e) => props.onMouseMove?.(e)}
194
+ onMouseOver={(e) => props.onMouseOver?.(e)}
195
+ onMouseOut={(e) => props.onMouseOut?.(e)}
196
+ onMouseUp={(e) => props.onMouseUp?.(e)}
197
+ onTouchEnd={(e) => props.onTouchEnd?.(e)}
198
+ onTouchMove={(e) => props.onTouchMove?.(e)}
199
+ onTouchStart={(e) => props.onTouchStart?.(e)}
200
+ >
201
+ {props.children}
202
+ </div>
203
+ </>
204
+ )
205
+ /* eslint-enable solid/reactivity */
206
+ }
207
+
208
+ function ReadSizeOnceDiv(props: WrapperDivProps) {
209
+ /* eslint-disable solid/reactivity -- props.height/width seed signal once at setup; innerRef is a callback ref */
210
+ const [sizes, setSizes] = createSignal<{
211
+ containerWidth: number
212
+ containerHeight: number
213
+ }>(
214
+ untrack(() => ({
215
+ containerHeight: getNumberOrZero(props.height),
216
+ containerWidth: getNumberOrZero(props.width),
217
+ })),
218
+ )
219
+ /* eslint-enable solid/reactivity */
220
+
221
+ function setContainerSize(newWidth: number, newHeight: number) {
222
+ const roundedWidth = Math.round(newWidth)
223
+ const roundedHeight = Math.round(newHeight)
224
+ const prev = untrack(sizes)
225
+ if (prev.containerWidth === roundedWidth && prev.containerHeight === roundedHeight) {
226
+ return
227
+ }
228
+ setSizes({ containerHeight: roundedHeight, containerWidth: roundedWidth })
229
+ }
230
+
231
+ /* eslint-disable-next-line solid/reactivity -- callback ref assigned via ref={innerRef}; linter false-positive on function-as-ref */
232
+ function innerRef(node: HTMLDivElement) {
233
+ if (typeof props.ref === "function") {
234
+ props.ref(node)
235
+ }
236
+ const { width: containerWidth, height: containerHeight } = node.getBoundingClientRect()
237
+ setContainerSize(containerWidth, containerHeight)
238
+ }
239
+
240
+ /* eslint-disable solid/reactivity -- innerRef is a callback ref; ref={fn} is the correct Solid pattern */
241
+ return (
242
+ <>
243
+ <ReportChartSize width={sizes().containerWidth} height={sizes().containerHeight} />
244
+ <div
245
+ ref={innerRef}
246
+ class={props.class}
247
+ style={pxifyStyle(props.style)}
248
+ onClick={(e) => props.onClick?.(e)}
249
+ onContextMenu={(e) => props.onContextMenu?.(e)}
250
+ onDblClick={(e) => props.onDblClick?.(e)}
251
+ onFocusIn={() => props.onFocusIn?.()}
252
+ onFocusOut={() => props.onFocusOut?.()}
253
+ onKeyDown={(e) => props.onKeyDown?.(e)}
254
+ onMouseDown={(e) => props.onMouseDown?.(e)}
255
+ onMouseEnter={(e) => props.onMouseEnter?.(e)}
256
+ onMouseLeave={(e) => props.onMouseLeave?.(e)}
257
+ onMouseMove={(e) => props.onMouseMove?.(e)}
258
+ onMouseOver={(e) => props.onMouseOver?.(e)}
259
+ onMouseOut={(e) => props.onMouseOut?.(e)}
260
+ onMouseUp={(e) => props.onMouseUp?.(e)}
261
+ onTouchEnd={(e) => props.onTouchEnd?.(e)}
262
+ onTouchMove={(e) => props.onTouchMove?.(e)}
263
+ onTouchStart={(e) => props.onTouchStart?.(e)}
264
+ >
265
+ {props.children}
266
+ </div>
267
+ </>
268
+ )
269
+ /* eslint-enable solid/reactivity */
270
+ }
271
+
272
+ function StaticDiv(props: WrapperDivProps & { width: number; height: number }) {
273
+ return (
274
+ <>
275
+ <ReportChartSize width={props.width} height={props.height} />
276
+ <div
277
+ ref={props.ref}
278
+ class={props.class}
279
+ style={pxifyStyle(props.style)}
280
+ onClick={(e) => props.onClick?.(e)}
281
+ onContextMenu={(e) => props.onContextMenu?.(e)}
282
+ onDblClick={(e) => props.onDblClick?.(e)}
283
+ onFocusIn={() => props.onFocusIn?.()}
284
+ onFocusOut={() => props.onFocusOut?.()}
285
+ onKeyDown={(e) => props.onKeyDown?.(e)}
286
+ onMouseDown={(e) => props.onMouseDown?.(e)}
287
+ onMouseEnter={(e) => props.onMouseEnter?.(e)}
288
+ onMouseLeave={(e) => props.onMouseLeave?.(e)}
289
+ onMouseMove={(e) => props.onMouseMove?.(e)}
290
+ onMouseOver={(e) => props.onMouseOver?.(e)}
291
+ onMouseOut={(e) => props.onMouseOut?.(e)}
292
+ onMouseUp={(e) => props.onMouseUp?.(e)}
293
+ onTouchEnd={(e) => props.onTouchEnd?.(e)}
294
+ onTouchMove={(e) => props.onTouchMove?.(e)}
295
+ onTouchStart={(e) => props.onTouchStart?.(e)}
296
+ >
297
+ {props.children}
298
+ </div>
299
+ </>
300
+ )
301
+ }
302
+
303
+ /* eslint-disable solid/reactivity -- props.width/height type checks are structural guards at component setup; NonResponsiveDiv branches once at mount */
304
+ function NonResponsiveDiv(props: WrapperDivProps) {
305
+ const width = untrack(() => props.width)
306
+ const height = untrack(() => props.height)
307
+ /* When width or height are percentages or CSS short names, read size from DOM once */
308
+ if (typeof width === "string" || typeof height === "string") {
309
+ return <ReadSizeOnceDiv {...props} />
310
+ }
311
+ /* When both are numbers, use them directly */
312
+ if (typeof width === "number" && typeof height === "number") {
313
+ return <StaticDiv {...props} width={props.width as number} height={props.height as number} />
314
+ }
315
+ /* eslint-enable solid/reactivity */
316
+ /* When width/height are undefined, render wrapper div without reporting size */
317
+ return (
318
+ <>
319
+ <ReportChartSize
320
+ width={props.width as number | undefined}
321
+ height={props.height as number | undefined}
322
+ />
323
+ <div
324
+ ref={props.ref}
325
+ class={props.class}
326
+ style={pxifyStyle(props.style)}
327
+ onClick={(e) => props.onClick?.(e)}
328
+ onContextMenu={(e) => props.onContextMenu?.(e)}
329
+ onDblClick={(e) => props.onDblClick?.(e)}
330
+ onFocusIn={() => props.onFocusIn?.()}
331
+ onFocusOut={() => props.onFocusOut?.()}
332
+ onKeyDown={(e) => props.onKeyDown?.(e)}
333
+ onMouseDown={(e) => props.onMouseDown?.(e)}
334
+ onMouseEnter={(e) => props.onMouseEnter?.(e)}
335
+ onMouseLeave={(e) => props.onMouseLeave?.(e)}
336
+ onMouseMove={(e) => props.onMouseMove?.(e)}
337
+ onMouseOver={(e) => props.onMouseOver?.(e)}
338
+ onMouseOut={(e) => props.onMouseOut?.(e)}
339
+ onMouseUp={(e) => props.onMouseUp?.(e)}
340
+ onTouchEnd={(e) => props.onTouchEnd?.(e)}
341
+ onTouchMove={(e) => props.onTouchMove?.(e)}
342
+ onTouchStart={(e) => props.onTouchStart?.(e)}
343
+ >
344
+ {props.children}
345
+ </div>
346
+ </>
347
+ )
348
+ }
349
+
350
+ function getWrapperDivComponent(responsive: boolean) {
351
+ return responsive ? ResponsiveDiv : NonResponsiveDiv
352
+ }
353
+
354
+ export function RechartsWrapper(props: RechartsWrapperProps) {
355
+ let _containerRef: HTMLDivElement | null = null
356
+ const ctx = useChartStore()
357
+ const newCtx = useOptionalChartState()
358
+ const [tooltipPortal, setTooltipPortal] = createSignal<HTMLElement | null>(null)
359
+ const [legendPortal, setLegendPortal] = createSignal<HTMLElement | null>(null)
360
+
361
+ const setScaleRef = useReportScale()
362
+
363
+ const responsiveContainerCalculations = useResponsiveContainerContext()
364
+ const width = () =>
365
+ responsiveContainerCalculations.width > 0 ? responsiveContainerCalculations.width : props.width
366
+ const height = () =>
367
+ responsiveContainerCalculations.height > 0
368
+ ? responsiveContainerCalculations.height
369
+ : props.height
370
+
371
+ function innerRef(node: HTMLDivElement) {
372
+ setScaleRef(node)
373
+ if (typeof props.ref === "function") {
374
+ props.ref(node)
375
+ }
376
+ setTooltipPortal(node)
377
+ setLegendPortal(node)
378
+ _containerRef = node
379
+ }
380
+
381
+ function toHTMLMousePointer(e: MouseEvent): HTMLMousePointer {
382
+ return {
383
+ clientX: e.clientX,
384
+ clientY: e.clientY,
385
+ currentTarget: e.currentTarget as HTMLElement,
386
+ }
387
+ }
388
+
389
+ /* GOTCHA-016-C: dedupe across native mouseenter + mouseover bindings.
390
+ Solid binds 1:1; both fire on real entry. Shared flag prevents double-dispatch. */
391
+ /* null until the first enter/leave: a leave with no prior enter still dispatches, like React. */
392
+ let pointerInside: boolean | null = null
393
+
394
+ function myOnClick(e: MouseEvent) {
395
+ ctx?.events.handleMouseClick(toHTMLMousePointer(e))
396
+ ctx?.events.handleExternalEvent(e, props.onClick)
397
+ }
398
+
399
+ function myOnMouseEnter(e: MouseEvent) {
400
+ ctx?.events.handleMouseMove(toHTMLMousePointer(e))
401
+ if (pointerInside !== true) {
402
+ pointerInside = true
403
+ ctx?.events.handleExternalEvent(e, props.onMouseEnter)
404
+ }
405
+ }
406
+
407
+ function myOnMouseLeave(e: MouseEvent) {
408
+ {
409
+ newCtx?.setState("tooltip", "axisInteraction", "hover", "active", false)
410
+ newCtx?.setState("tooltip", "itemInteraction", "hover", "active", false)
411
+ }
412
+ if (pointerInside !== false) {
413
+ pointerInside = false
414
+ ctx?.events.handleExternalEvent(e, props.onMouseLeave)
415
+ }
416
+ }
417
+
418
+ /* React's onMouseEnter wrapped both mouseenter + mouseover under one synthetic
419
+ event. Solid wires native events 1:1, so test helpers calling fireEvent.mouseOver
420
+ bypass mouseenter and the tooltip never activates. Bind mouseover to the same
421
+ dispatch path; handleMouseMove is idempotent on identical pointer state. */
422
+ function myOnMouseOver(e: MouseEvent) {
423
+ ctx?.events.handleMouseMove(toHTMLMousePointer(e))
424
+ /* Mirror native mouseenter -> user onMouseEnter handler dispatch.
425
+ Dedupe so binding both mouseenter+mouseover doesn't double-fire. */
426
+ if (pointerInside !== true) {
427
+ pointerInside = true
428
+ ctx?.events.handleExternalEvent(e, props.onMouseEnter)
429
+ }
430
+ }
431
+
432
+ /* Symmetric pair for mouseLeave. mouseout bubbles from descendants too —
433
+ only dispatch when the pointer actually leaves the wrapper container,
434
+ matching mouseleave semantics. */
435
+ function myOnMouseOut(e: MouseEvent) {
436
+ const wrapper = e.currentTarget as HTMLElement
437
+ const next = e.relatedTarget as Node | null
438
+ if (next != null && wrapper.contains(next)) {
439
+ return
440
+ }
441
+ {
442
+ newCtx?.setState("tooltip", "axisInteraction", "hover", "active", false)
443
+ newCtx?.setState("tooltip", "itemInteraction", "hover", "active", false)
444
+ }
445
+ if (pointerInside !== false) {
446
+ pointerInside = false
447
+ ctx?.events.handleExternalEvent(e, props.onMouseLeave)
448
+ }
449
+ }
450
+
451
+ function myOnMouseMove(e: MouseEvent) {
452
+ ctx?.events.handleMouseMove(toHTMLMousePointer(e))
453
+ ctx?.events.handleExternalEvent(e, props.onMouseMove)
454
+ }
455
+
456
+ function onFocusIn() {
457
+ ctx?.events.handleFocus()
458
+ }
459
+
460
+ function onFocusOut() {
461
+ ctx?.events.handleBlur()
462
+ }
463
+
464
+ function onKeyDown(e: KeyboardEvent) {
465
+ ctx?.events.handleKeyDown(e.key)
466
+ }
467
+
468
+ function myOnContextMenu(e: MouseEvent) {
469
+ ctx?.events.handleExternalEvent(e, props.onContextMenu)
470
+ }
471
+
472
+ function myOnDoubleClick(e: MouseEvent) {
473
+ ctx?.events.handleExternalEvent(e, props.onDoubleClick)
474
+ }
475
+
476
+ function myOnMouseDown(e: MouseEvent) {
477
+ ctx?.events.handleExternalEvent(e, props.onMouseDown)
478
+ }
479
+
480
+ function myOnMouseUp(e: MouseEvent) {
481
+ ctx?.events.handleExternalEvent(e, props.onMouseUp)
482
+ }
483
+
484
+ function myOnTouchStart(e: TouchEvent) {
485
+ ctx?.events.handleExternalEvent(e, props.onTouchStart)
486
+ }
487
+
488
+ /*
489
+ * onTouchMove is special because it behaves different from mouse events.
490
+ * Mouse events have 'enter' + 'leave' combo that notify us when the mouse is over
491
+ * a certain element. Touch events don't have that; touch only gives us
492
+ * start (finger down), end (finger up) and move (finger moving).
493
+ * So we need to figure out which element the user is touching
494
+ * ourselves. Fortunately, there's a convenient method for that:
495
+ * https://developer.mozilla.org/en-US/docs/Web/API/Document/elementFromPoint
496
+ */
497
+ function myOnTouchMove(e: TouchEvent) {
498
+ const dispatchTouchEvents = props.dispatchTouchEvents ?? true
499
+ if (dispatchTouchEvents) {
500
+ ctx?.events.handleTouchMove(e)
501
+ }
502
+ ctx?.events.handleExternalEvent(e, props.onTouchMove)
503
+ }
504
+
505
+ function myOnTouchEnd(e: TouchEvent) {
506
+ ctx?.events.handleExternalEvent(e, props.onTouchEnd)
507
+ }
508
+
509
+ /* eslint-disable-next-line solid/reactivity -- props.responsive determines wrapper component once at mount; stable structural check */
510
+ const WrapperDiv = getWrapperDivComponent(untrack(() => props.responsive))
511
+
512
+ return (
513
+ <TooltipPortalContext value={tooltipPortal}>
514
+ <LegendPortalContext value={legendPortal}>
515
+ <WrapperDiv
516
+ width={width() ?? props.style?.width}
517
+ height={height() ?? props.style?.height}
518
+ class={clsx("recharts-wrapper", props.class)}
519
+ style={{
520
+ cursor: "default",
521
+ height:
522
+ typeof height() === "number" ? `${height()}px` : (height() as string | undefined),
523
+ position: "relative",
524
+ width: typeof width() === "number" ? `${width()}px` : (width() as string | undefined),
525
+ ...props.style,
526
+ }}
527
+ onClick={myOnClick}
528
+ onContextMenu={myOnContextMenu}
529
+ onDblClick={myOnDoubleClick}
530
+ onFocusIn={onFocusIn}
531
+ onFocusOut={onFocusOut}
532
+ onKeyDown={onKeyDown}
533
+ onMouseDown={myOnMouseDown}
534
+ onMouseEnter={myOnMouseEnter}
535
+ onMouseLeave={myOnMouseLeave}
536
+ onMouseMove={myOnMouseMove}
537
+ onMouseOver={myOnMouseOver}
538
+ onMouseOut={myOnMouseOut}
539
+ onMouseUp={myOnMouseUp}
540
+ onTouchEnd={myOnTouchEnd}
541
+ onTouchMove={myOnTouchMove}
542
+ onTouchStart={myOnTouchStart}
543
+ ref={innerRef}
544
+ >
545
+ <EventSynchronizer />
546
+ {props.children}
547
+ </WrapperDiv>
548
+ </LegendPortalContext>
549
+ </TooltipPortalContext>
550
+ )
551
+ }