solid-recharts 1.0.0 → 2.0.0-beta.1

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 (488) hide show
  1. package/package.json +4 -6
  2. package/src/animation/AnimatedItems.tsx +4 -2
  3. package/src/animation/CSSTransitionAnimate.tsx +39 -41
  4. package/src/animation/JavascriptAnimate.tsx +41 -45
  5. package/src/cartesian/Area.tsx +4 -4
  6. package/src/cartesian/AreaRevealShape.tsx +1 -1
  7. package/src/cartesian/Bar.tsx +21 -33
  8. package/src/cartesian/BarStack.tsx +5 -5
  9. package/src/cartesian/Brush.tsx +15 -19
  10. package/src/cartesian/CartesianAxis.tsx +4 -4
  11. package/src/cartesian/CartesianGrid.tsx +5 -5
  12. package/src/cartesian/ErrorBar.tsx +7 -9
  13. package/src/cartesian/Funnel.tsx +3 -3
  14. package/src/cartesian/GraphicalItemClipPath.tsx +1 -1
  15. package/src/cartesian/Line.tsx +16 -18
  16. package/src/cartesian/LineDrawShape.tsx +13 -14
  17. package/src/cartesian/ReferenceArea.tsx +4 -4
  18. package/src/cartesian/ReferenceDot.tsx +4 -4
  19. package/src/cartesian/ReferenceLine.tsx +4 -4
  20. package/src/cartesian/RenderedTicksReporter.tsx +17 -19
  21. package/src/cartesian/Scatter.tsx +3 -3
  22. package/src/cartesian/XAxis.tsx +1 -1
  23. package/src/cartesian/YAxis.tsx +33 -35
  24. package/src/cartesian/ZAxis.tsx +2 -3
  25. package/src/chart/AreaChart.tsx +1 -1
  26. package/src/chart/BarChart.tsx +1 -1
  27. package/src/chart/CartesianChart.tsx +3 -4
  28. package/src/chart/CategoricalChart.tsx +5 -5
  29. package/src/chart/ComposedChart.tsx +1 -1
  30. package/src/chart/FunnelChart.tsx +1 -1
  31. package/src/chart/LineChart.tsx +1 -1
  32. package/src/chart/PieChart.tsx +3 -4
  33. package/src/chart/PolarChart.tsx +3 -4
  34. package/src/chart/RadarChart.tsx +3 -4
  35. package/src/chart/RadialBarChart.tsx +3 -7
  36. package/src/chart/RechartsWrapper.tsx +24 -14
  37. package/src/chart/Sankey.tsx +6 -9
  38. package/src/chart/ScatterChart.tsx +1 -1
  39. package/src/chart/SunburstChart.tsx +4 -5
  40. package/src/chart/Treemap.tsx +4 -5
  41. package/src/component/ActivePoints.tsx +6 -6
  42. package/src/component/Cell.tsx +5 -23
  43. package/src/component/Cursor.tsx +3 -3
  44. package/src/component/DefaultLegendContent.tsx +6 -8
  45. package/src/component/DefaultTooltipContent.tsx +10 -14
  46. package/src/component/Dots.tsx +5 -5
  47. package/src/component/Label.tsx +10 -13
  48. package/src/component/LabelList.tsx +7 -12
  49. package/src/component/Legend.tsx +21 -26
  50. package/src/component/ResponsiveContainer.tsx +49 -52
  51. package/src/component/Text.tsx +5 -5
  52. package/src/component/Tooltip.tsx +18 -21
  53. package/src/component/TooltipBoundingBox.tsx +16 -18
  54. package/src/component/responsiveContainerUtils.ts +1 -1
  55. package/src/container/ClipPathProvider.tsx +3 -3
  56. package/src/container/Layer.tsx +5 -5
  57. package/src/container/RootSurface.tsx +1 -1
  58. package/src/container/Surface.tsx +6 -5
  59. package/src/context/ErrorBarContext.tsx +2 -2
  60. package/src/context/PanoramaContext.tsx +2 -2
  61. package/src/context/RegisterGraphicalItemId.tsx +2 -4
  62. package/src/context/chartDataContext.tsx +23 -26
  63. package/src/context/chartLayoutContext.tsx +12 -16
  64. package/src/polar/Pie.tsx +12 -13
  65. package/src/polar/PolarAngleAxis.tsx +3 -3
  66. package/src/polar/PolarGrid.tsx +5 -5
  67. package/src/polar/PolarRadiusAxis.tsx +3 -3
  68. package/src/polar/Radar.tsx +3 -3
  69. package/src/polar/RadialBar.tsx +3 -3
  70. package/src/shape/Cross.tsx +5 -5
  71. package/src/shape/Curve.tsx +7 -6
  72. package/src/shape/Dot.tsx +4 -4
  73. package/src/shape/Polygon.tsx +5 -5
  74. package/src/shape/Rectangle.tsx +20 -22
  75. package/src/shape/Sector.tsx +5 -5
  76. package/src/shape/Symbols.tsx +5 -5
  77. package/src/shape/Trapezoid.tsx +27 -29
  78. package/src/state/RechartsStoreProvider.tsx +3 -5
  79. package/src/state/ReportChartProps.tsx +6 -8
  80. package/src/state/ReportEventSettings.tsx +6 -8
  81. package/src/state/ReportMainChartProps.tsx +9 -11
  82. package/src/state/ReportPolarOptions.tsx +13 -15
  83. package/src/state/SetLegendPayload.ts +1 -1
  84. package/src/state/SetTooltipEntrySettings.tsx +1 -1
  85. package/src/state/brushSlice.ts +8 -10
  86. package/src/state/cartesianAxisSlice.ts +38 -46
  87. package/src/state/chartDataSlice.ts +23 -29
  88. package/src/state/errorBarSlice.ts +16 -22
  89. package/src/state/eventSettingsSlice.ts +9 -11
  90. package/src/state/graphicalItemsSlice.ts +13 -17
  91. package/src/state/layoutSlice.ts +19 -27
  92. package/src/state/legendSlice.ts +18 -24
  93. package/src/state/optionsSlice.ts +6 -8
  94. package/src/state/polarAxisSlice.ts +13 -21
  95. package/src/state/polarOptionsSlice.ts +14 -16
  96. package/src/state/referenceElementsSlice.ts +19 -25
  97. package/src/state/registerInStore.ts +13 -15
  98. package/src/state/renderedTicksSlice.ts +7 -11
  99. package/src/state/rootPropsSlice.ts +14 -16
  100. package/src/state/tooltipSlice.ts +95 -115
  101. package/src/state/unregisterOnCleanup.ts +20 -5
  102. package/src/state/zIndexSlice.ts +42 -50
  103. package/src/synchronisation/useChartSynchronisation.tsx +217 -213
  104. package/src/util/ActiveShapeUtils.tsx +2 -2
  105. package/src/util/BarUtils.tsx +3 -5
  106. package/src/util/FunnelUtils.tsx +1 -1
  107. package/src/util/RadialBarUtils.tsx +3 -4
  108. package/src/util/createCartesianCharts.tsx +1 -1
  109. package/src/util/createPolarCharts.tsx +1 -1
  110. package/src/util/svgPropertiesAndEvents.ts +1 -1
  111. package/src/util/tooltip/translate.ts +2 -2
  112. package/src/util/types.ts +2 -2
  113. package/src/zIndex/ZIndexLayer.tsx +68 -39
  114. package/src/zIndex/ZIndexPortal.tsx +25 -29
  115. package/test/_data.ts +408 -0
  116. package/test/animation/AnimationController.typed.spec.ts +53 -0
  117. package/test/animation/AnimationControllerImpl.spec.ts +271 -0
  118. package/test/animation/CSSTransitionAnimate.timing.spec.tsx +473 -0
  119. package/test/animation/JavascriptAnimate.spec.tsx +62 -0
  120. package/test/animation/RechartsAnimation.spec.ts +636 -0
  121. package/test/animation/easing.spec.ts +218 -0
  122. package/test/animation/legacyAnimationLengthChange.spec.tsx +803 -0
  123. package/test/animation/matchBy.spec.ts +467 -0
  124. package/test/animation/mockAnimationController.ts +40 -0
  125. package/test/animation/mockControllerAnimationManager.ts +143 -0
  126. package/test/animation/mockTimeoutController.ts +114 -0
  127. package/test/animation/timeoutController.spec.ts +138 -0
  128. package/test/animation/useAnimationStartSnapshot.spec.ts +147 -0
  129. package/test/animation/util.spec.ts +28 -0
  130. package/test/cartesian/Area.animation.spec.tsx +363 -0
  131. package/test/cartesian/Area.range.spec.tsx +54 -0
  132. package/test/cartesian/Area.spec.tsx +1202 -0
  133. package/test/cartesian/Area.stacked.render.spec.tsx +69 -0
  134. package/test/cartesian/Area.typed.spec.tsx +209 -0
  135. package/test/cartesian/Axis.integration.spec.tsx +158 -0
  136. package/test/cartesian/Bar/Bar.csstransition.spec.tsx +299 -0
  137. package/test/cartesian/Bar/Bar.spec.tsx +2314 -0
  138. package/test/cartesian/Bar/Bar.typed.spec.tsx +192 -0
  139. package/test/cartesian/Bar.animation.spec.tsx +426 -0
  140. package/test/cartesian/Bar.stackDomain.spec.tsx +66 -0
  141. package/test/cartesian/Bar.stacked.render.spec.tsx +53 -0
  142. package/test/cartesian/Bar.truncateByDomain.spec.tsx +237 -0
  143. package/test/cartesian/Bar.zeroDimensionFiltering.spec.tsx +336 -0
  144. package/test/cartesian/BarStack.spec.tsx +91 -0
  145. package/test/cartesian/Brush.keyboard.spec.tsx +88 -0
  146. package/test/cartesian/Brush.panorama.spec.tsx +41 -0
  147. package/test/cartesian/Brush.props.spec.tsx +63 -0
  148. package/test/cartesian/Brush.render.spec.tsx +117 -0
  149. package/test/cartesian/Brush.spec.tsx +522 -0
  150. package/test/cartesian/Brush.stacked.spec.tsx +221 -0
  151. package/test/cartesian/CartesianAxis.render.spec.tsx +50 -0
  152. package/test/cartesian/CartesianAxis.spec.tsx +396 -0
  153. package/test/cartesian/CartesianGrid.render.spec.tsx +39 -0
  154. package/test/cartesian/CartesianGrid.spec.tsx +2103 -0
  155. package/test/cartesian/ErrorBar.render.spec.tsx +69 -0
  156. package/test/cartesian/ErrorBar.spec.tsx +2414 -0
  157. package/test/cartesian/Funnel.animation.spec.tsx +241 -0
  158. package/test/cartesian/Funnel.spec.tsx +226 -0
  159. package/test/cartesian/Funnel.typed.spec.tsx +221 -0
  160. package/test/cartesian/GraphicalItemClipPath.scale-behavior.spec.tsx +627 -0
  161. package/test/cartesian/GraphicalItemClipPath.spec.tsx +427 -0
  162. package/test/cartesian/Line.animation.spec.tsx +643 -0
  163. package/test/cartesian/Line.sparseAnimationPath.spec.tsx +98 -0
  164. package/test/cartesian/Line.spec.tsx +471 -0
  165. package/test/cartesian/Line.typed.spec.tsx +152 -0
  166. package/test/cartesian/ReferenceArea.render.spec.tsx +63 -0
  167. package/test/cartesian/ReferenceArea.spec.tsx +663 -0
  168. package/test/cartesian/ReferenceArea.typed.spec.tsx +74 -0
  169. package/test/cartesian/ReferenceDot.render.spec.tsx +55 -0
  170. package/test/cartesian/ReferenceDot.spec.tsx +462 -0
  171. package/test/cartesian/ReferenceDot.typed.spec.tsx +76 -0
  172. package/test/cartesian/ReferenceLine/ReferenceLine.panorama.spec.tsx +184 -0
  173. package/test/cartesian/ReferenceLine/ReferenceLine.spec.tsx +744 -0
  174. package/test/cartesian/ReferenceLine/ReferenceLine.typed.spec.tsx +74 -0
  175. package/test/cartesian/ReferenceLine/getEndPoints.spec.ts +399 -0
  176. package/test/cartesian/ReferenceLine.render.spec.tsx +134 -0
  177. package/test/cartesian/Scatter.animation.spec.tsx +381 -0
  178. package/test/cartesian/Scatter.render.spec.tsx +61 -0
  179. package/test/cartesian/Scatter.spec.tsx +406 -0
  180. package/test/cartesian/Scatter.typed.spec.tsx +153 -0
  181. package/test/cartesian/XAxis/XAxis.barSize.spec.tsx +336 -0
  182. package/test/cartesian/XAxis/XAxis.brush.spec.tsx +266 -0
  183. package/test/cartesian/XAxis/XAxis.categorydomain.spec.tsx +872 -0
  184. package/test/cartesian/XAxis/XAxis.dataKey.spec.tsx +86 -0
  185. package/test/cartesian/XAxis/XAxis.datatypes.spec.tsx +127 -0
  186. package/test/cartesian/XAxis/XAxis.hide.spec.tsx +106 -0
  187. package/test/cartesian/XAxis/XAxis.multiaxis.spec.tsx +336 -0
  188. package/test/cartesian/XAxis/XAxis.numberdomain.spec.tsx +1466 -0
  189. package/test/cartesian/XAxis/XAxis.padding.spec.tsx +758 -0
  190. package/test/cartesian/XAxis/XAxis.padding_clip.spec.tsx +65 -0
  191. package/test/cartesian/XAxis/XAxis.state.spec.tsx +355 -0
  192. package/test/cartesian/XAxis/XAxis.tick.spec.tsx +493 -0
  193. package/test/cartesian/XAxis/XAxis.timescale.spec.tsx +233 -0
  194. package/test/cartesian/XAxis/XAxis.type.spec.tsx +107 -0
  195. package/test/cartesian/XAxis/XAxis.typed.spec.tsx +102 -0
  196. package/test/cartesian/XAxis/XAxis.vertical.spec.tsx +265 -0
  197. package/test/cartesian/XAxis.tickFormatter.spec.tsx +54 -0
  198. package/test/cartesian/YAxis/YAxis.7362.derivedDomain.spec.tsx +230 -0
  199. package/test/cartesian/YAxis/YAxis.7362.spec.tsx +104 -0
  200. package/test/cartesian/YAxis/YAxis.interval-zero.spec.tsx +88 -0
  201. package/test/cartesian/YAxis/YAxis.label.spec.tsx +219 -0
  202. package/test/cartesian/YAxis/YAxis.spec.tsx +1595 -0
  203. package/test/cartesian/YAxis/YAxis.tick.spec.tsx +428 -0
  204. package/test/cartesian/YAxis/YAxis.tickFormatter.spec.tsx +54 -0
  205. package/test/cartesian/YAxis/YAxis.ticks.spec.tsx +263 -0
  206. package/test/cartesian/YAxis/YAxis.type.spec.tsx +107 -0
  207. package/test/cartesian/YAxis/YAxis.typed.spec.tsx +102 -0
  208. package/test/cartesian/ZAxis.spec.tsx +300 -0
  209. package/test/cartesian/ZAxis.typed.spec.tsx +33 -0
  210. package/test/cartesian/__snapshots__/Brush.spec.tsx.snap +5 -0
  211. package/test/cartesian/axisLineAndStroke.spec.tsx +72 -0
  212. package/test/cartesian/getCartesianPosition.spec.ts +907 -0
  213. package/test/cartesian/getEquidistantTicks.spec.ts +88 -0
  214. package/test/cartesian/getTicks.spec.ts +378 -0
  215. package/test/cartesian/miscFeatureGaps.spec.tsx +89 -0
  216. package/test/cartesian/useAnimatedLineLength.spec.ts +168 -0
  217. package/test/chart/AccessibilityLayer.spec.tsx +569 -0
  218. package/test/chart/AccessibilityScans.spec.tsx +286 -0
  219. package/test/chart/AreaChart.spec.tsx +409 -0
  220. package/test/chart/AreaChart.stacked.spec.tsx +1407 -0
  221. package/test/chart/AreaChart.typed.spec.tsx +39 -0
  222. package/test/chart/BarChart.spec.tsx +3719 -0
  223. package/test/chart/BarChart.typed.spec.tsx +60 -0
  224. package/test/chart/CategoricalChart.spec.tsx +255 -0
  225. package/test/chart/ComposedChart.spec.tsx +199 -0
  226. package/test/chart/ComposedChart.typed.spec.tsx +39 -0
  227. package/test/chart/FunnelChart.spec.tsx +215 -0
  228. package/test/chart/FunnelChart.typed.spec.tsx +39 -0
  229. package/test/chart/LineChart.multiseries.spec.tsx +50 -0
  230. package/test/chart/LineChart.smoke.spec.tsx +50 -0
  231. package/test/chart/LineChart.spec.tsx +930 -0
  232. package/test/chart/LineChart.typed.spec.tsx +39 -0
  233. package/test/chart/NicheChartTooltip.spec.tsx +81 -0
  234. package/test/chart/PieChart.spec.tsx +793 -0
  235. package/test/chart/PieChart.typed.spec.tsx +39 -0
  236. package/test/chart/RadarChart.spec.tsx +530 -0
  237. package/test/chart/RadarChart.typed.spec.tsx +39 -0
  238. package/test/chart/RadialBarChart.5966.spec.tsx +48 -0
  239. package/test/chart/RadialBarChart.spec.tsx +679 -0
  240. package/test/chart/RadialBarChart.typed.spec.tsx +39 -0
  241. package/test/chart/RechartsWrapper.spec.tsx +83 -0
  242. package/test/chart/Sankey.content.spec.tsx +46 -0
  243. package/test/chart/Sankey.spec.tsx +952 -0
  244. package/test/chart/Sankey.typed.spec.tsx +29 -0
  245. package/test/chart/ScatterChart.spec.tsx +2613 -0
  246. package/test/chart/ScatterChart.typed.spec.tsx +39 -0
  247. package/test/chart/SunburstChart.spec.tsx +146 -0
  248. package/test/chart/Treemap.animation.spec.tsx +52 -0
  249. package/test/chart/Treemap.spec.tsx +1003 -0
  250. package/test/chart/Treemap.typed.spec.tsx +26 -0
  251. package/test/chart/chartEvents.spec.tsx +127 -0
  252. package/test/chart/responsive.spec.tsx +620 -0
  253. package/test/component/Cell.render.spec.tsx +155 -0
  254. package/test/component/Cell.spec.tsx +12 -0
  255. package/test/component/Cursor.spec.tsx +186 -0
  256. package/test/component/DefaultTooltipContent.spec.tsx +102 -0
  257. package/test/component/Label.render.spec.tsx +63 -0
  258. package/test/component/Label.spec.tsx +686 -0
  259. package/test/component/Label.typed.spec.tsx +46 -0
  260. package/test/component/LabelList.spec.tsx +188 -0
  261. package/test/component/Legend.itemSorter.spec.tsx +704 -0
  262. package/test/component/Legend.render.spec.tsx +92 -0
  263. package/test/component/Legend.spec.tsx +2213 -0
  264. package/test/component/Legend.typed.spec.tsx +22 -0
  265. package/test/component/ResponsiveContainer.spec.tsx +523 -0
  266. package/test/component/ResponsiveContainerDataTest.spec.tsx +51 -0
  267. package/test/component/Text.spec.tsx +415 -0
  268. package/test/component/Text.typed.spec.tsx +46 -0
  269. package/test/component/Tooltip/ActiveDot.spec.tsx +370 -0
  270. package/test/component/Tooltip/Tooltip.animation.spec.tsx +209 -0
  271. package/test/component/Tooltip/Tooltip.content.spec.tsx +128 -0
  272. package/test/component/Tooltip/Tooltip.formatter.spec.tsx +152 -0
  273. package/test/component/Tooltip/Tooltip.includeHidden.spec.tsx +79 -0
  274. package/test/component/Tooltip/Tooltip.multipleDataArrays.spec.tsx +165 -0
  275. package/test/component/Tooltip/Tooltip.offset.spec.tsx +113 -0
  276. package/test/component/Tooltip/Tooltip.state.spec.tsx +74 -0
  277. package/test/component/Tooltip/Tooltip.sync.spec.tsx +639 -0
  278. package/test/component/Tooltip/defaultIndex.spec.tsx +227 -0
  279. package/test/component/Tooltip/graphicalItem.formatter.spec.tsx +138 -0
  280. package/test/component/Tooltip/itemSorter.spec.tsx +2815 -0
  281. package/test/component/Tooltip/tooltipEventType.spec.tsx +344 -0
  282. package/test/component/Tooltip/tooltipMouseHoverSelectors.ts +41 -0
  283. package/test/component/Tooltip/tooltipTestHelpers.tsx +162 -0
  284. package/test/component/Tooltip.defaultIndex.spec.tsx +48 -0
  285. package/test/component/Tooltip.hover.spec.tsx +61 -0
  286. package/test/component/Tooltip.item.spec.tsx +54 -0
  287. package/test/component/Tooltip.keyboard.spec.tsx +51 -0
  288. package/test/component/Tooltip.payload.spec.tsx +1716 -0
  289. package/test/component/Tooltip.touch.spec.tsx +39 -0
  290. package/test/component/Tooltip.visibility.spec.tsx +1889 -0
  291. package/test/component/TooltipBoundingBox.spec.tsx +89 -0
  292. package/test/component/responsiveContainerUtils.spec.ts +205 -0
  293. package/test/container/ClipPath.spec.tsx +602 -0
  294. package/test/container/chartDimensions.spec.tsx +368 -0
  295. package/test/context/chartLayoutContext.spec.tsx +378 -0
  296. package/test/helper/ExpectAxisDomain.tsx +27 -0
  297. package/test/helper/assertNotNull.ts +6 -0
  298. package/test/helper/assertZIndexLayerOrder.ts +19 -0
  299. package/test/helper/createSelectorTestCase.tsx +176 -0
  300. package/test/helper/expectAnimatedPieAngles.ts +100 -0
  301. package/test/helper/expectAnimatedPiePaths.ts +78 -0
  302. package/test/helper/expectAreaCurve.ts +15 -0
  303. package/test/helper/expectAxisTicks.ts +48 -0
  304. package/test/helper/expectBars.ts +54 -0
  305. package/test/helper/expectFunctionReturning.ts +58 -0
  306. package/test/helper/expectLabel.ts +32 -0
  307. package/test/helper/expectLastCalledWith.ts +48 -0
  308. package/test/helper/expectLine.ts +20 -0
  309. package/test/helper/expectPieSectors.ts +80 -0
  310. package/test/helper/expectScale.ts +37 -0
  311. package/test/helper/expectScatterPoints.ts +52 -0
  312. package/test/helper/expectStackGroups.ts +144 -0
  313. package/test/helper/mockAxes.ts +22 -0
  314. package/test/helper/mockGetBoundingClientRect.ts +66 -0
  315. package/test/helper/mockHTMLElementProperty.ts +19 -0
  316. package/test/helper/mockTouchingElement.ts +27 -0
  317. package/test/helper/offsetHelpers.ts +19 -0
  318. package/test/helper/parameterizedTestCases.tsx +99 -0
  319. package/test/helper/produceState.ts +32 -0
  320. package/test/helper/selectorTestHelpers.tsx +63 -0
  321. package/test/helper/trim.spec.ts +35 -0
  322. package/test/helper/trim.ts +11 -0
  323. package/test/hooks/useActiveTooltipDataPoints.spec.tsx +358 -0
  324. package/test/hooks/useAxisDomain.spec.tsx +361 -0
  325. package/test/hooks/useAxisScale.spec.tsx +283 -0
  326. package/test/hooks/useAxisTicks.spec.tsx +130 -0
  327. package/test/hooks/useOffset.spec.tsx +248 -0
  328. package/test/hooks/useTooltipStateHooks.spec.tsx +109 -0
  329. package/test/polar/Pie/Pie-TwoLevelPieChart.spec.tsx +135 -0
  330. package/test/polar/Pie/Pie.spec.tsx +784 -0
  331. package/test/polar/Pie/Pie.typed.spec.tsx +78 -0
  332. package/test/polar/Pie.animation.spec.tsx +529 -0
  333. package/test/polar/PieWithLegend.animation.spec.tsx +142 -0
  334. package/test/polar/PolarAngleAxis/PolarAngleAxis.events.spec.tsx +76 -0
  335. package/test/polar/PolarAngleAxis/PolarAngleAxis.spec.tsx +2079 -0
  336. package/test/polar/PolarAngleAxis/PolarAngleAxis.typed.spec.tsx +102 -0
  337. package/test/polar/PolarAngleAxis.render.spec.tsx +79 -0
  338. package/test/polar/PolarGrid.render.spec.tsx +75 -0
  339. package/test/polar/PolarGrid.spec.tsx +918 -0
  340. package/test/polar/PolarLegendPerRow.render.spec.tsx +85 -0
  341. package/test/polar/PolarRadiusAxis.events.spec.tsx +65 -0
  342. package/test/polar/PolarRadiusAxis.render.spec.tsx +52 -0
  343. package/test/polar/PolarRadiusAxis.spec.tsx +991 -0
  344. package/test/polar/PolarRadiusAxis.typed.spec.tsx +84 -0
  345. package/test/polar/PolarTooltipLegend.render.spec.tsx +80 -0
  346. package/test/polar/Radar.animation.spec.tsx +570 -0
  347. package/test/polar/Radar.render.spec.tsx +71 -0
  348. package/test/polar/Radar.spec.tsx +265 -0
  349. package/test/polar/Radar.typed.spec.tsx +119 -0
  350. package/test/polar/RadialBar/RadialBar.spec.tsx +1521 -0
  351. package/test/polar/RadialBar/RadialBar.typed.spec.tsx +132 -0
  352. package/test/polar/RadialBar.animation.spec.tsx +375 -0
  353. package/test/polar/RadialBar.render.spec.tsx +66 -0
  354. package/test/polar/RadialBar.stacked.spec.tsx +57 -0
  355. package/test/setup.ts +84 -0
  356. package/test/shape/ActiveShape.spec.tsx +181 -0
  357. package/test/shape/Cross.spec.tsx +60 -0
  358. package/test/shape/Cross.typed.spec.tsx +26 -0
  359. package/test/shape/Curve.spec.tsx +368 -0
  360. package/test/shape/Curve.typed.spec.tsx +69 -0
  361. package/test/shape/Dot.spec.tsx +73 -0
  362. package/test/shape/Dot.typed.spec.tsx +30 -0
  363. package/test/shape/Polygon.spec.tsx +357 -0
  364. package/test/shape/Polygon.typed.spec.tsx +28 -0
  365. package/test/shape/Rectangle.animation.spec.tsx +451 -0
  366. package/test/shape/Rectangle.spec.tsx +68 -0
  367. package/test/shape/Rectangle.typed.spec.tsx +24 -0
  368. package/test/shape/Sector.spec.tsx +76 -0
  369. package/test/shape/Sector.typed.spec.tsx +24 -0
  370. package/test/shape/Symbols.spec.tsx +43 -0
  371. package/test/shape/Symbols.typed.spec.tsx +24 -0
  372. package/test/shape/Trapezoid.spec.tsx +50 -0
  373. package/test/shape/Trapezoid.typed.spec.tsx +24 -0
  374. package/test/shape/__snapshots__/Cross.spec.tsx.snap +62 -0
  375. package/test/shape/__snapshots__/Curve.spec.tsx.snap +460 -0
  376. package/test/shape/__snapshots__/Polygon.spec.tsx.snap +58 -0
  377. package/test/shape/__snapshots__/Rectangle.spec.tsx.snap +117 -0
  378. package/test/shape/__snapshots__/Sector.spec.tsx.snap +71 -0
  379. package/test/shape/__snapshots__/Trapezoid.spec.tsx.snap +64 -0
  380. package/test/state/chartDataSlice.spec.ts +53 -0
  381. package/test/state/createCollectionActions.spec.ts +87 -0
  382. package/test/state/createSelector.spec.ts +158 -0
  383. package/test/state/externalEventsMiddleware.spec.ts +178 -0
  384. package/test/state/graphicalItemsSlice.spec.ts +92 -0
  385. package/test/state/hooks.spec.tsx +68 -0
  386. package/test/state/legendSlice.spec.ts +44 -0
  387. package/test/state/mouseEventsMiddleware.spec.ts +75 -0
  388. package/test/state/optionsSlice.spec.ts +19 -0
  389. package/test/state/referenceElementsSlice.spec.ts +84 -0
  390. package/test/state/registerInStore.spec.tsx +101 -0
  391. package/test/state/selectors/areaSelectors.spec.tsx +77 -0
  392. package/test/state/selectors/axisSelectors.spec.tsx +1418 -0
  393. package/test/state/selectors/barStackSelectors.spec.tsx +752 -0
  394. package/test/state/selectors/brushSelectors.spec.tsx +30 -0
  395. package/test/state/selectors/cartesianAxisSlice.spec.ts +96 -0
  396. package/test/state/selectors/combineNiceTicks.spec.ts +207 -0
  397. package/test/state/selectors/combiners/combineActiveTooltipIndex.spec.ts +61 -0
  398. package/test/state/selectors/combiners/combineAllBarPositions.spec.ts +39 -0
  399. package/test/state/selectors/combiners/combineConfiguredScale.spec.ts +56 -0
  400. package/test/state/selectors/combiners/combineDisplayedStackedData.spec.ts +123 -0
  401. package/test/state/selectors/combiners/combineRealScaleType.spec.ts +80 -0
  402. package/test/state/selectors/containerSelectors.spec.tsx +168 -0
  403. package/test/state/selectors/dataSelectors.spec.tsx +136 -0
  404. package/test/state/selectors/legendSelectors.spec.tsx +113 -0
  405. package/test/state/selectors/lineSelectors.spec.tsx +60 -0
  406. package/test/state/selectors/pieSelectors.spec.tsx +72 -0
  407. package/test/state/selectors/radarSelectors.spec.tsx +496 -0
  408. package/test/state/selectors/rootPropsSelectors.spec.tsx +169 -0
  409. package/test/state/selectors/scatterSelectors.spec.tsx +47 -0
  410. package/test/state/selectors/selectActiveTooltipIndex.spec.tsx +234 -0
  411. package/test/state/selectors/selectAllAxes.spec.tsx +18 -0
  412. package/test/state/selectors/selectAxisDomain.spec.tsx +21 -0
  413. package/test/state/selectors/selectAxisDomainIncludingNiceTicks.spec.tsx +19 -0
  414. package/test/state/selectors/selectAxisRangeWithReverse.spec.tsx +22 -0
  415. package/test/state/selectors/selectAxisScale.spec.tsx +91 -0
  416. package/test/state/selectors/selectBarRectangles.stackOffset.spec.tsx +503 -0
  417. package/test/state/selectors/selectBaseAxis.spec.tsx +56 -0
  418. package/test/state/selectors/selectCartesianItemsSettings.spec.tsx +57 -0
  419. package/test/state/selectors/selectChartOffset.spec.tsx +26 -0
  420. package/test/state/selectors/selectDisplayedData.spec.tsx +282 -0
  421. package/test/state/selectors/selectIsTooltipActive.spec.tsx +231 -0
  422. package/test/state/selectors/selectNumericalDomain.spec.tsx +21 -0
  423. package/test/state/selectors/selectRealScaleType.spec.tsx +19 -0
  424. package/test/state/selectors/selectStackGroups.spec.tsx +322 -0
  425. package/test/state/selectors/selectXAxisPosition.spec.tsx +22 -0
  426. package/test/state/selectors/selectYAxisPosition.spec.tsx +22 -0
  427. package/test/state/selectors/selectorMemoization.spec.tsx +136 -0
  428. package/test/state/selectors/selectors.spec.tsx +1613 -0
  429. package/test/state/throttling.spec.ts +200 -0
  430. package/test/state/zIndexSlice.spec.ts +85 -0
  431. package/test/synchronisation/useChartSynchronisation.spec.tsx +225 -0
  432. package/test/util/BarUtils.spec.ts +39 -0
  433. package/test/util/CartesianUtils/CartesianUtils.spec.ts +261 -0
  434. package/test/util/CartesianUtils/rectWithPoints.spec.ts +48 -0
  435. package/test/util/ChartUtils/ChartUtils.spec.ts +491 -0
  436. package/test/util/ChartUtils/appendOffsetOfLegend.spec.ts +136 -0
  437. package/test/util/ChartUtils/appendOffsetOfLegend.spec.tsx +133 -0
  438. package/test/util/ChartUtils/getCateCoordinateOfLine.spec.ts +97 -0
  439. package/test/util/ChartUtils/getStackedData.spec.ts +416 -0
  440. package/test/util/ChartUtils/truncateByDomain.spec.ts +70 -0
  441. package/test/util/DataUtils.spec.ts +385 -0
  442. package/test/util/DomUtils.spec.tsx +117 -0
  443. package/test/util/FunnelUtils.spec.tsx +70 -0
  444. package/test/util/Global.spec.ts +11 -0
  445. package/test/util/LRUCache.spec.ts +81 -0
  446. package/test/util/LogUtils.spec.ts +45 -0
  447. package/test/util/PolarUtils.spec.ts +66 -0
  448. package/test/util/ReduceCssCalcPrototype.spec.ts +141 -0
  449. package/test/util/ShallowEqual.spec.ts +102 -0
  450. package/test/util/TickUtils.spec.ts +29 -0
  451. package/test/util/createChartHelpers.spec.tsx +210 -0
  452. package/test/util/cursor/getCursorPoints.spec.ts +136 -0
  453. package/test/util/cursor/getCursorRectangle.spec.ts +50 -0
  454. package/test/util/cursor/getRadialCursorPoints.spec.ts +36 -0
  455. package/test/util/errorValue.spec.ts +69 -0
  456. package/test/util/getEveryNth.spec.ts +39 -0
  457. package/test/util/getRadiusAndStrokeWidthFromDot.spec.ts +51 -0
  458. package/test/util/getRelativeCoordinate.spec.ts +250 -0
  459. package/test/util/getSliced.spec.ts +45 -0
  460. package/test/util/isDomainSpecifiedByUser.spec.ts +207 -0
  461. package/test/util/isWellBehavedNumber.spec.ts +54 -0
  462. package/test/util/payload/getUniqPayload.spec.ts +56 -0
  463. package/test/util/propsAreEqual.spec.ts +75 -0
  464. package/test/util/round.spec.ts +112 -0
  465. package/test/util/scale/arithmetic.spec.ts +61 -0
  466. package/test/util/scale/createCategoricalInverse.spec.ts +84 -0
  467. package/test/util/scale/getNiceTickValues.spec.ts +421 -0
  468. package/test/util/scale/getTickValuesFixedDomain.spec.ts +155 -0
  469. package/test/util/svgPropertiesAndEvents.spec.tsx +206 -0
  470. package/test/util/svgPropertiesNoEvents.spec.tsx +228 -0
  471. package/test/util/tooltip/translate.spec.ts +396 -0
  472. package/test/util/useAnimationId.spec.tsx +59 -0
  473. package/test/util/useElementOffset.spec.tsx +173 -0
  474. package/test/util/usePrefersReducedMotion.spec.ts +54 -0
  475. package/test/util/useUniqueId.spec.ts +99 -0
  476. package/test/utils/diagnostics-allowlist.ts +18 -0
  477. package/test/utils/diagnostics.ts +58 -0
  478. package/test/zIndex/AllZIndexPortals.spec.tsx +83 -0
  479. package/test/zIndex/DefaultZIndexes.spec.ts +80 -0
  480. package/test/zIndex/DynamicZIndex.spec.tsx +102 -0
  481. package/test/zIndex/ZIndexLayer.portalOwner.spec.tsx +125 -0
  482. package/test/zIndex/componentZIndex.spec.tsx +255 -0
  483. package/test/zIndex/getZIndexFromUnknown.spec.ts +51 -0
  484. package/test/zIndex/multiChartZIndexIsolation.spec.tsx +90 -0
  485. package/test/zIndex/zIndexSelectors.spec.ts +172 -0
  486. package/test-results/.last-run.json +4 -0
  487. package/tsconfig.json +11 -0
  488. package/src/util/DirectPortal.tsx +0 -107
@@ -0,0 +1,3719 @@
1
+ // Subset port of recharts 3.8.1 test/chart/BarChart.spec.tsx (commit 7a23854) —
2
+ // the payoff of the Bar vertical: rectangles drawn from data via the band scale.
3
+ //
4
+ // Minimal/Tier-A-adapted: asserts the parity-critical facts (one
5
+ // `.recharts-bar-rectangle` per data point, inside `.recharts-bar`, with sane
6
+ // geometry). The full spec (background bars, stacks, labels, animation, exact
7
+ // per-bar coords) comes online when those features land. `flush()` after render
8
+ // because the bar registers via an effect and its rectangles compute from the store.
9
+ import { beforeEach, describe, expect, it, vi } from "vitest";
10
+ import { createEffect, createSignal, flush } from "solid-js";
11
+ import { render, fireEvent } from "@solidjs/testing-library";
12
+ import { BarChart, Bar, ComposedChart, Rectangle, Tooltip, XAxis, YAxis } from "../../src";
13
+ import type { BarChartProps, BarProps, BarRectangleItem } from "../../src";
14
+ import { PageData, boxPlotData } from "../_data";
15
+ import {
16
+ useChartHeight,
17
+ useChartWidth,
18
+ useMargin,
19
+ useOffsetInternal,
20
+ useViewBox,
21
+ } from "../../src/context/chartLayoutContext";
22
+ import { useOffset, usePlotArea } from "../../src/hooks";
23
+ import { useClipPathId } from "../../src/container/ClipPathProvider";
24
+ import { expectBars } from "../helper/expectBars";
25
+ import { useAppSelector } from "../../src/state/hooks";
26
+ import { expectScale } from "../helper/expectScale";
27
+ import {
28
+ selectAllBarPositions,
29
+ selectAllVisibleBars,
30
+ selectAxisBandSize,
31
+ selectBarBandSize,
32
+ selectBarCartesianAxisSize,
33
+ selectBarPosition,
34
+ selectBarRectangles,
35
+ selectBarSizeList,
36
+ selectMaxBarSize,
37
+ } from "../../src/state/selectors/barSelectors";
38
+ import {
39
+ selectAxisScale,
40
+ selectCategoricalDomain,
41
+ selectTicksOfGraphicalItem,
42
+ selectUnfilteredCartesianItems,
43
+ } from "../../src/state/selectors/axisSelectors";
44
+ import {
45
+ selectBarCategoryGap,
46
+ selectBarGap,
47
+ selectRootMaxBarSize,
48
+ } from "../../src/state/selectors/rootPropsSelectors";
49
+ import type { BarSettings } from "../../src/state/types/BarSettings";
50
+ import type { CartesianGraphicalItemSettings } from "../../src/state/graphicalItemsSlice";
51
+ import { defaultAxisId } from "../../src/state/cartesianAxisSlice";
52
+ import { createSelectorTestCase } from "../helper/createSelectorTestCase";
53
+ import { expectLastCalledWith } from "../helper/expectLastCalledWith";
54
+ import { assertNotNull } from "../helper/assertNotNull";
55
+ import { mockGetBoundingClientRect } from "../helper/mockGetBoundingClientRect";
56
+ import {
57
+ expectTooltipNotVisible,
58
+ expectTooltipPayload,
59
+ getTooltip,
60
+ hideTooltip,
61
+ showTooltipOnCoordinate,
62
+ } from "../component/Tooltip/tooltipTestHelpers";
63
+ import { barChartMouseHoverTooltipSelector } from "../component/Tooltip/tooltipMouseHoverSelectors";
64
+
65
+ // Shared with the appended vendor describes (recharts' top-level `data`).
66
+ const data = [
67
+ { name: "food", uv: 400, pv: 2400 },
68
+ { name: "cosmetic", uv: 300, pv: 4567 },
69
+ { name: "storage", uv: 300, pv: 1398 },
70
+ { name: "digital", uv: 200, pv: 9800 },
71
+ ];
72
+
73
+ describe("<BarChart />", () => {
74
+ it("renders four labels when label=true", () => {
75
+ const { container } = render(() => (
76
+ <BarChart width={100} height={50} data={data}>
77
+ <Bar isAnimationActive={false} dataKey="uv" label fill="#ff7300" />
78
+ </BarChart>
79
+ ));
80
+ flush();
81
+
82
+ expect(container.querySelectorAll(".recharts-label-list")).toHaveLength(1);
83
+ expect(container.querySelectorAll(".recharts-label")).toHaveLength(4);
84
+ });
85
+
86
+ it("renders a tooltip shell when Tooltip item is added", () => {
87
+ const { container } = render(() => (
88
+ <BarChart width={100} height={50} data={data}>
89
+ <Bar dataKey="uv" stackId="test" fill="#ff7300" isAnimationActive={false} />
90
+ <Bar dataKey="pv" stackId="test" fill="#387908" isAnimationActive={false} />
91
+ <Tooltip />
92
+ </BarChart>
93
+ ));
94
+ flush();
95
+
96
+ expect(container.querySelectorAll(".recharts-default-tooltip")).toHaveLength(1);
97
+ expect(container.querySelectorAll(".recharts-tooltip-wrapper")).toHaveLength(1);
98
+ });
99
+
100
+ it("renders empty when data is empty", () => {
101
+ const { container } = render(() => (
102
+ <BarChart width={100} height={50} data={[]}>
103
+ <Bar dataKey="uv" label fill="#ff7300" isAnimationActive={false} />
104
+ </BarChart>
105
+ ));
106
+ flush();
107
+
108
+ expect(container.querySelectorAll(".recharts-bar-rectangle")).toHaveLength(0);
109
+ expect(container.querySelectorAll(".recharts-label")).toHaveLength(0);
110
+ });
111
+
112
+ // Hovers the chart surface near the first bar, drives the active-bar rAF staging,
113
+ // and asserts a single `.recharts-active-bar` is shown, then hidden on mouseOut.
114
+ // Ported from recharts' `assertActiveBarInteractions` (rAF staging → two timer
115
+ // flushes), adapted to the Solid harness (showTooltipOnCoordinate + flush()).
116
+ function assertActiveBarInteractions(container: HTMLElement) {
117
+ expect(container.querySelectorAll(".recharts-active-bar")).toHaveLength(0);
118
+
119
+ showTooltipOnCoordinate(container, barChartMouseHoverTooltipSelector, {
120
+ clientX: 100,
121
+ clientY: 100,
122
+ });
123
+ // First timer clears the mouse-event handler; second shows the active bar after
124
+ // its initial inactive render (so the CSS transition can start).
125
+ vi.runOnlyPendingTimers();
126
+ flush();
127
+ vi.runOnlyPendingTimers();
128
+ flush();
129
+
130
+ expect(container.querySelectorAll(".recharts-active-bar")).toHaveLength(1);
131
+
132
+ hideTooltip(container, barChartMouseHoverTooltipSelector);
133
+ vi.runOnlyPendingTimers();
134
+ flush();
135
+
136
+ expect(container.querySelectorAll(".recharts-active-bar")).toHaveLength(0);
137
+ }
138
+
139
+ describe("activeBar", () => {
140
+ beforeEach(() => {
141
+ mockGetBoundingClientRect({ width: 700, height: 200 });
142
+ });
143
+
144
+ it("does not render an active bar by default", () => {
145
+ const { container } = render(() => (
146
+ <BarChart width={700} height={200} data={data}>
147
+ <Bar dataKey="uv" stackId="test" fill="#ff7300" />
148
+ <Tooltip />
149
+ </BarChart>
150
+ ));
151
+ flush();
152
+
153
+ showTooltipOnCoordinate(container, barChartMouseHoverTooltipSelector, {
154
+ clientX: 100,
155
+ clientY: 100,
156
+ });
157
+ vi.runOnlyPendingTimers();
158
+ flush();
159
+ expect(container.querySelectorAll(".recharts-active-bar")).toHaveLength(0);
160
+ });
161
+
162
+ it("renders a customized active bar when activeBar is a function", () => {
163
+ const { container } = render(() => (
164
+ <BarChart width={700} height={200} data={data}>
165
+ <Bar
166
+ dataKey="uv"
167
+ stackId="test"
168
+ fill="#ff7300"
169
+ activeBar={(props) => <Rectangle {...props} />}
170
+ />
171
+ <Tooltip />
172
+ </BarChart>
173
+ ));
174
+ flush();
175
+ assertActiveBarInteractions(container);
176
+ });
177
+
178
+ it("renders a customized active bar when activeBar is a truthy boolean", () => {
179
+ const { container } = render(() => (
180
+ <BarChart width={700} height={200} data={data}>
181
+ <Bar dataKey="uv" stackId="test" fill="#ff7300" activeBar />
182
+ <Tooltip />
183
+ </BarChart>
184
+ ));
185
+ flush();
186
+ assertActiveBarInteractions(container);
187
+ });
188
+
189
+ it("does not render a customized active bar when activeBar is a falsy boolean", () => {
190
+ const { container } = render(() => (
191
+ <BarChart width={700} height={200} data={data}>
192
+ <Bar dataKey="uv" stackId="test" fill="#ff7300" activeBar={false} />
193
+ <Tooltip />
194
+ </BarChart>
195
+ ));
196
+ flush();
197
+
198
+ showTooltipOnCoordinate(container, barChartMouseHoverTooltipSelector, {
199
+ clientX: 100,
200
+ clientY: 100,
201
+ });
202
+ vi.runOnlyPendingTimers();
203
+ flush();
204
+ expect(container.querySelectorAll(".recharts-active-bar")).toHaveLength(0);
205
+ });
206
+
207
+ it("renders a customized active bar when activeBar is an object", () => {
208
+ const { container } = render(() => (
209
+ <BarChart width={700} height={200} data={data}>
210
+ <Bar
211
+ dataKey="uv"
212
+ stackId="test"
213
+ fill="#ff7300"
214
+ // recharts' BarShapeProps is SVG-prop-spreadable (strokeWidth et al);
215
+ // the ported BarShapeProps types only the geometry/presentation subset,
216
+ // so cast the object-form activeBar to the prop type (the extra SVG
217
+ // attrs flow through to the rendered Rectangle just as in recharts).
218
+ activeBar={{ strokeWidth: 4, fill: "green" } as BarProps["activeBar"]}
219
+ />
220
+ <Tooltip />
221
+ </BarChart>
222
+ ));
223
+ flush();
224
+ assertActiveBarInteractions(container);
225
+ });
226
+ });
227
+
228
+ describe("shape", () => {
229
+ it("renders a customized shape when shape is a function", () => {
230
+ const { container } = render(() => (
231
+ <BarChart width={100} height={50} data={data}>
232
+ <Bar
233
+ dataKey="uv"
234
+ label
235
+ fill="#ff7300"
236
+ isAnimationActive={false}
237
+ shape={(props) => <circle class="customized-shape" cx={props.x} cy={props.y} r={8} />}
238
+ />
239
+ </BarChart>
240
+ ));
241
+ flush();
242
+ expect(container.querySelectorAll(".customized-shape")).toHaveLength(4);
243
+ });
244
+ });
245
+
246
+ describe("state integration", () => {
247
+ it("should report margin, and update after it changes", () => {
248
+ const spy = vi.fn();
249
+ const [margin, setMargin] = createSignal({ top: 1, right: 2, bottom: 3, left: 4 });
250
+ const Spy = (): null => {
251
+ const m = useMargin();
252
+ createEffect(
253
+ () => m(),
254
+ (v) => spy(v),
255
+ );
256
+ return null;
257
+ };
258
+ render(() => (
259
+ <BarChart width={100} height={100} margin={margin()}>
260
+ <Spy />
261
+ </BarChart>
262
+ ));
263
+ flush();
264
+ expectLastCalledWith(spy, { bottom: 3, left: 4, right: 2, top: 1 });
265
+
266
+ setMargin({ top: 10, right: 20, bottom: 30, left: 40 });
267
+ flush();
268
+ expectLastCalledWith(spy, { bottom: 30, left: 40, right: 20, top: 10 });
269
+ });
270
+ });
271
+
272
+ it("renders bars in a vertical BarChart", () => {
273
+ const { container } = render(() => (
274
+ <BarChart width={100} height={50} data={data} layout="vertical">
275
+ <XAxis type="number" />
276
+ <YAxis type="category" dataKey="name" />
277
+ <Bar dataKey="uv" fill="#ff7300" isAnimationActive={false} />
278
+ <Bar dataKey="pv" fill="#387908" isAnimationActive={false} />
279
+ </BarChart>
280
+ ));
281
+ flush();
282
+
283
+ const layers = container.querySelectorAll(".recharts-bar .recharts-bar-rectangle");
284
+ expect(layers).toHaveLength(8);
285
+ const path0 = layers[0]!.querySelector("path.recharts-rectangle");
286
+ expect(path0).toHaveAttribute("height", "1");
287
+ expect(path0).toHaveAttribute("x", "65");
288
+ const path7 = layers[7]!.querySelector("path.recharts-rectangle");
289
+ expect(path7).toHaveAttribute("fill", "#387908");
290
+ });
291
+
292
+ // Any reactive-graph diagnostic fired during this test fails it via the global
293
+ // guard in test/setup.ts (no per-test wrapper needed).
294
+ it("renders one rectangle per data point from the band scale", () => {
295
+ const { container } = render(() => (
296
+ <BarChart
297
+ width={400}
298
+ height={400}
299
+ data={PageData}
300
+ margin={{ top: 20, right: 20, bottom: 20, left: 20 }}
301
+ >
302
+ <Bar dataKey="uv" fill="#ff7300" isAnimationActive={false} />
303
+ </BarChart>
304
+ ));
305
+ flush();
306
+
307
+ const paths = container.querySelectorAll(
308
+ ".recharts-bar .recharts-bar-rectangle path.recharts-rectangle",
309
+ );
310
+ expect(paths).toHaveLength(PageData.length);
311
+ expect(paths[0]).toHaveAttribute("fill", "#ff7300");
312
+ // Exact geometry (matches recharts' algorithm): band scale over 6 categories
313
+ // in [20, 380] → bandSize 60; barCategoryGap 10% → offset 6, size 48, so each
314
+ // bar's x = bandStart(20 + 60·i) + 6. Heights from the linear uv scale
315
+ // [0, 400] → range [380, 20]: uv 400→h 360, 300→270, 200→180, 278→250.2, 189→170.1.
316
+ const geometry = [...paths].map((r) =>
317
+ ["x", "y", "width", "height"].map((a) => r.getAttribute(a)).join(","),
318
+ );
319
+ expect(geometry).toEqual([
320
+ "26,20,48,360",
321
+ "86,110,48,270",
322
+ "146,110,48,270",
323
+ "206,200,48,180",
324
+ "266,129.8,48,250.2",
325
+ "326,209.9,48,170.1",
326
+ ]);
327
+ });
328
+
329
+ it("renders a custom bar via the shape render prop (replacing the default rect)", () => {
330
+ const { container } = render(() => (
331
+ <BarChart
332
+ width={400}
333
+ height={400}
334
+ data={PageData}
335
+ margin={{ top: 20, right: 20, bottom: 20, left: 20 }}
336
+ >
337
+ <Bar
338
+ dataKey="uv"
339
+ isAnimationActive={false}
340
+ shape={(item) => <circle class="custom-bar" data-x={item.x} data-h={item.height} />}
341
+ />
342
+ </BarChart>
343
+ ));
344
+ flush();
345
+
346
+ // No default rectangle shapes; one custom circle per data point, each wrapped in
347
+ // a `.recharts-bar-rectangle` layer that received the bar's geometry.
348
+ expect(container.querySelectorAll("rect.recharts-bar-rectangle")).toHaveLength(0);
349
+ const circles = container.querySelectorAll("circle.custom-bar");
350
+ expect(circles).toHaveLength(PageData.length);
351
+ expect(circles[0]!.getAttribute("data-x")).toBe("26");
352
+ expect(circles[0]!.getAttribute("data-h")).toBe("360");
353
+ });
354
+
355
+ it("activates the item tooltip when a custom bar shape is hovered", () => {
356
+ const { container } = render(() => (
357
+ <BarChart
358
+ width={400}
359
+ height={400}
360
+ data={PageData}
361
+ margin={{ top: 20, right: 20, bottom: 20, left: 20 }}
362
+ >
363
+ <Bar
364
+ dataKey="uv"
365
+ isAnimationActive={false}
366
+ shape={(item) => <circle class="custom-bar" data-h={item.height} />}
367
+ />
368
+ <Tooltip shared={false} />
369
+ </BarChart>
370
+ ));
371
+ flush();
372
+
373
+ // Handlers live on the wrapping `.recharts-bar-rectangle` layer (mouseenter
374
+ // doesn't bubble from the circle, so hover the layer itself).
375
+ const layers = container.querySelectorAll(".recharts-bar .recharts-bar-rectangle");
376
+ fireEvent.mouseEnter(layers[0]!);
377
+ flush();
378
+
379
+ const values = [...container.querySelectorAll(".recharts-tooltip-item-value")].map(
380
+ (n) => n.textContent,
381
+ );
382
+ expect(values).toEqual([String(PageData[0]!.uv)]);
383
+ });
384
+
385
+ describe("BarChart layout context", () => {
386
+ it("should provide viewBox", () => {
387
+ const spy = vi.fn();
388
+ const Comp = (): null => {
389
+ const viewBox = useViewBox();
390
+ createEffect(
391
+ () => viewBox(),
392
+ (v) => spy(v),
393
+ );
394
+ return null;
395
+ };
396
+ render(() => (
397
+ <BarChart width={100} height={50}>
398
+ <Comp />
399
+ </BarChart>
400
+ ));
401
+
402
+ expect(spy).toHaveBeenCalledWith({ x: 5, y: 5, width: 90, height: 40 });
403
+ });
404
+
405
+ it("should provide clipPathId", () => {
406
+ const spy = vi.fn();
407
+ const Comp = (): null => {
408
+ createEffect(
409
+ () => useClipPathId(),
410
+ (v) => spy(v),
411
+ );
412
+ return null;
413
+ };
414
+ render(() => (
415
+ <BarChart width={100} height={50}>
416
+ <Comp />
417
+ </BarChart>
418
+ ));
419
+
420
+ expect(spy).toHaveBeenCalledWith(expect.stringMatching(/recharts\d+-clip/));
421
+ });
422
+
423
+ it("should provide width", () => {
424
+ const spy = vi.fn();
425
+ const Comp = (): null => {
426
+ const width = useChartWidth();
427
+ createEffect(
428
+ () => width(),
429
+ (v) => spy(v),
430
+ );
431
+ return null;
432
+ };
433
+ render(() => (
434
+ <BarChart width={100} height={50}>
435
+ <Comp />
436
+ </BarChart>
437
+ ));
438
+
439
+ expect(spy).toHaveBeenCalledWith(100);
440
+ });
441
+
442
+ it("should provide height", () => {
443
+ const spy = vi.fn();
444
+ const Comp = (): null => {
445
+ const height = useChartHeight();
446
+ createEffect(
447
+ () => height(),
448
+ (v) => spy(v),
449
+ );
450
+ return null;
451
+ };
452
+ render(() => (
453
+ <BarChart width={100} height={50}>
454
+ <Comp />
455
+ </BarChart>
456
+ ));
457
+
458
+ expect(spy).toHaveBeenCalledWith(50);
459
+ });
460
+ });
461
+ });
462
+
463
+ describe("bar categories", () => {
464
+ it("should render bars grouped in a category if they share the same xAxis tick", () => {
465
+ const { container } = render(() => (
466
+ <BarChart width={500} height={300} data={data}>
467
+ <XAxis dataKey="name" />
468
+ <Bar dataKey="uv" isAnimationActive={false} />
469
+ <Bar dataKey="pv" isAnimationActive={false} />
470
+ </BarChart>
471
+ ));
472
+
473
+ expectBars(container, [
474
+ {
475
+ d: "M 17.25,254.6 h 47 v 10.4 h -47 Z",
476
+ height: "10.4",
477
+ radius: "0",
478
+ width: "47",
479
+ x: "17.25",
480
+ y: "254.6",
481
+ },
482
+ {
483
+ d: "M 139.75,257.2 h 47 v 7.8 h -47 Z",
484
+ height: "7.8",
485
+ radius: "0",
486
+ width: "47",
487
+ x: "139.75",
488
+ y: "257.2",
489
+ },
490
+ {
491
+ d: "M 262.25,257.2 h 47 v 7.8 h -47 Z",
492
+ height: "7.8",
493
+ radius: "0",
494
+ width: "47",
495
+ x: "262.25",
496
+ y: "257.2",
497
+ },
498
+ {
499
+ d: "M 384.75,259.8 h 47 v 5.2 h -47 Z",
500
+ height: "5.2",
501
+ radius: "0",
502
+ width: "47",
503
+ x: "384.75",
504
+ y: "259.8",
505
+ },
506
+ {
507
+ d: "M 68.25,202.6 h 47 v 62.4 h -47 Z",
508
+ height: "62.4",
509
+ radius: "0",
510
+ width: "47",
511
+ x: "68.25",
512
+ y: "202.6",
513
+ },
514
+ {
515
+ d: "M 190.75,146.258 h 47 v 118.742 h -47 Z",
516
+ height: "118.742",
517
+ radius: "0",
518
+ width: "47",
519
+ x: "190.75",
520
+ y: "146.258",
521
+ },
522
+ {
523
+ d: "M 313.25,228.652 h 47 v 36.348 h -47 Z",
524
+ height: "36.348",
525
+ radius: "0",
526
+ width: "47",
527
+ x: "313.25",
528
+ y: "228.652",
529
+ },
530
+ {
531
+ d: "M 435.75,10.2 h 47 v 254.8 h -47 Z",
532
+ height: "254.8",
533
+ radius: "0",
534
+ width: "47",
535
+ x: "435.75",
536
+ y: "10.2",
537
+ },
538
+ ]);
539
+ });
540
+
541
+ describe("barGap as a number", () => {
542
+ it("should increase the gap between bars in a category", () => {
543
+ const { container } = render(() => (
544
+ <BarChart width={500} height={300} data={data} barGap={9}>
545
+ <XAxis dataKey="name" />
546
+ <Bar dataKey="uv" isAnimationActive={false} />
547
+ <Bar dataKey="pv" isAnimationActive={false} />
548
+ </BarChart>
549
+ ));
550
+
551
+ expectBars(container, [
552
+ {
553
+ x: "17.25",
554
+ y: "254.6",
555
+ width: "45",
556
+ height: "10.4",
557
+ radius: "0",
558
+ d: "M 17.25,254.6 h 45 v 10.4 h -45 Z",
559
+ },
560
+ {
561
+ x: "139.75",
562
+ y: "257.2",
563
+ width: "45",
564
+ height: "7.8",
565
+ radius: "0",
566
+ d: "M 139.75,257.2 h 45 v 7.8 h -45 Z",
567
+ },
568
+ {
569
+ x: "262.25",
570
+ y: "257.2",
571
+ width: "45",
572
+ height: "7.8",
573
+ radius: "0",
574
+ d: "M 262.25,257.2 h 45 v 7.8 h -45 Z",
575
+ },
576
+ {
577
+ x: "384.75",
578
+ y: "259.8",
579
+ width: "45",
580
+ height: "5.2",
581
+ radius: "0",
582
+ d: "M 384.75,259.8 h 45 v 5.2 h -45 Z",
583
+ },
584
+ {
585
+ x: "71.25",
586
+ y: "202.6",
587
+ width: "45",
588
+ height: "62.4",
589
+ radius: "0",
590
+ d: "M 71.25,202.6 h 45 v 62.4 h -45 Z",
591
+ },
592
+ {
593
+ x: "193.75",
594
+ y: "146.258",
595
+ width: "45",
596
+ height: "118.742",
597
+ radius: "0",
598
+ d: "M 193.75,146.258 h 45 v 118.742 h -45 Z",
599
+ },
600
+ {
601
+ x: "316.25",
602
+ y: "228.652",
603
+ width: "45",
604
+ height: "36.348",
605
+ radius: "0",
606
+ d: "M 316.25,228.652 h 45 v 36.348 h -45 Z",
607
+ },
608
+ {
609
+ x: "438.75",
610
+ y: "10.2",
611
+ width: "45",
612
+ height: "254.8",
613
+ radius: "0",
614
+ d: "M 438.75,10.2 h 45 v 254.8 h -45 Z",
615
+ },
616
+ ]);
617
+ });
618
+
619
+ it("should decrease the gap between bars in a category", () => {
620
+ const { container } = render(() => (
621
+ <BarChart width={500} height={300} data={data} barGap={2}>
622
+ <XAxis dataKey="name" />
623
+ <Bar dataKey="uv" isAnimationActive={false} />
624
+ <Bar dataKey="pv" isAnimationActive={false} />
625
+ </BarChart>
626
+ ));
627
+
628
+ expectBars(container, [
629
+ {
630
+ d: "M 17.25,254.6 h 48 v 10.4 h -48 Z",
631
+ height: "10.4",
632
+ radius: "0",
633
+ width: "48",
634
+ x: "17.25",
635
+ y: "254.6",
636
+ },
637
+ {
638
+ d: "M 139.75,257.2 h 48 v 7.8 h -48 Z",
639
+ height: "7.8",
640
+ radius: "0",
641
+ width: "48",
642
+ x: "139.75",
643
+ y: "257.2",
644
+ },
645
+ {
646
+ d: "M 262.25,257.2 h 48 v 7.8 h -48 Z",
647
+ height: "7.8",
648
+ radius: "0",
649
+ width: "48",
650
+ x: "262.25",
651
+ y: "257.2",
652
+ },
653
+ {
654
+ d: "M 384.75,259.8 h 48 v 5.2 h -48 Z",
655
+ height: "5.2",
656
+ radius: "0",
657
+ width: "48",
658
+ x: "384.75",
659
+ y: "259.8",
660
+ },
661
+ {
662
+ d: "M 67.25,202.6 h 48 v 62.4 h -48 Z",
663
+ height: "62.4",
664
+ radius: "0",
665
+ width: "48",
666
+ x: "67.25",
667
+ y: "202.6",
668
+ },
669
+ {
670
+ d: "M 189.75,146.258 h 48 v 118.742 h -48 Z",
671
+ height: "118.742",
672
+ radius: "0",
673
+ width: "48",
674
+ x: "189.75",
675
+ y: "146.258",
676
+ },
677
+ {
678
+ d: "M 312.25,228.652 h 48 v 36.348 h -48 Z",
679
+ height: "36.348",
680
+ radius: "0",
681
+ width: "48",
682
+ x: "312.25",
683
+ y: "228.652",
684
+ },
685
+ {
686
+ d: "M 434.75,10.2 h 48 v 254.8 h -48 Z",
687
+ height: "254.8",
688
+ radius: "0",
689
+ width: "48",
690
+ x: "434.75",
691
+ y: "10.2",
692
+ },
693
+ ]);
694
+ });
695
+ });
696
+
697
+ describe("barGap as a percentage", () => {
698
+ it("should set the gap between bars in a category", () => {
699
+ const { container } = render(() => (
700
+ <BarChart width={500} height={300} data={data} barGap="15%">
701
+ <XAxis dataKey="name" />
702
+ <Bar dataKey="uv" isAnimationActive={false} />
703
+ <Bar dataKey="pv" isAnimationActive={false} />
704
+ </BarChart>
705
+ ));
706
+
707
+ expectBars(container, [
708
+ {
709
+ x: "17.25",
710
+ y: "254.6",
711
+ width: "40",
712
+ height: "10.4",
713
+ radius: "0",
714
+ d: "M 17.25,254.6 h 40 v 10.4 h -40 Z",
715
+ },
716
+ {
717
+ x: "139.75",
718
+ y: "257.2",
719
+ width: "40",
720
+ height: "7.8",
721
+ radius: "0",
722
+ d: "M 139.75,257.2 h 40 v 7.8 h -40 Z",
723
+ },
724
+ {
725
+ x: "262.25",
726
+ y: "257.2",
727
+ width: "40",
728
+ height: "7.8",
729
+ radius: "0",
730
+ d: "M 262.25,257.2 h 40 v 7.8 h -40 Z",
731
+ },
732
+ {
733
+ x: "384.75",
734
+ y: "259.8",
735
+ width: "40",
736
+ height: "5.2",
737
+ radius: "0",
738
+ d: "M 384.75,259.8 h 40 v 5.2 h -40 Z",
739
+ },
740
+ {
741
+ x: "75.625",
742
+ y: "202.6",
743
+ width: "40",
744
+ height: "62.4",
745
+ radius: "0",
746
+ d: "M 75.625,202.6 h 40 v 62.4 h -40 Z",
747
+ },
748
+ {
749
+ x: "198.125",
750
+ y: "146.258",
751
+ width: "40",
752
+ height: "118.742",
753
+ radius: "0",
754
+ d: "M 198.125,146.258 h 40 v 118.742 h -40 Z",
755
+ },
756
+ {
757
+ x: "320.625",
758
+ y: "228.652",
759
+ width: "40",
760
+ height: "36.348",
761
+ radius: "0",
762
+ d: "M 320.625,228.652 h 40 v 36.348 h -40 Z",
763
+ },
764
+ {
765
+ x: "443.125",
766
+ y: "10.2",
767
+ width: "40",
768
+ height: "254.8",
769
+ radius: "0",
770
+ d: "M 443.125,10.2 h 40 v 254.8 h -40 Z",
771
+ },
772
+ ]);
773
+ });
774
+ });
775
+
776
+ describe("barCategoryGap as a number", () => {
777
+ it("should set the gap between bar categories", () => {
778
+ const { container } = render(() => (
779
+ <BarChart width={500} height={300} data={data} barCategoryGap={9}>
780
+ <XAxis dataKey="name" />
781
+ <Bar dataKey="uv" isAnimationActive={false} />
782
+ <Bar dataKey="pv" isAnimationActive={false} />
783
+ </BarChart>
784
+ ));
785
+
786
+ expectBars(container, [
787
+ {
788
+ d: "M 14,254.6 h 50 v 10.4 h -50 Z",
789
+ height: "10.4",
790
+ radius: "0",
791
+ width: "50",
792
+ x: "14",
793
+ y: "254.6",
794
+ },
795
+ {
796
+ d: "M 136.5,257.2 h 50 v 7.8 h -50 Z",
797
+ height: "7.8",
798
+ radius: "0",
799
+ width: "50",
800
+ x: "136.5",
801
+ y: "257.2",
802
+ },
803
+ {
804
+ d: "M 259,257.2 h 50 v 7.8 h -50 Z",
805
+ height: "7.8",
806
+ radius: "0",
807
+ width: "50",
808
+ x: "259",
809
+ y: "257.2",
810
+ },
811
+ {
812
+ d: "M 381.5,259.8 h 50 v 5.2 h -50 Z",
813
+ height: "5.2",
814
+ radius: "0",
815
+ width: "50",
816
+ x: "381.5",
817
+ y: "259.8",
818
+ },
819
+ {
820
+ d: "M 68,202.6 h 50 v 62.4 h -50 Z",
821
+ height: "62.4",
822
+ radius: "0",
823
+ width: "50",
824
+ x: "68",
825
+ y: "202.6",
826
+ },
827
+ {
828
+ d: "M 190.5,146.258 h 50 v 118.742 h -50 Z",
829
+ height: "118.742",
830
+ radius: "0",
831
+ width: "50",
832
+ x: "190.5",
833
+ y: "146.258",
834
+ },
835
+ {
836
+ d: "M 313,228.652 h 50 v 36.348 h -50 Z",
837
+ height: "36.348",
838
+ radius: "0",
839
+ width: "50",
840
+ x: "313",
841
+ y: "228.652",
842
+ },
843
+ {
844
+ d: "M 435.5,10.2 h 50 v 254.8 h -50 Z",
845
+ height: "254.8",
846
+ radius: "0",
847
+ width: "50",
848
+ x: "435.5",
849
+ y: "10.2",
850
+ },
851
+ ]);
852
+ });
853
+ });
854
+
855
+ describe("barCategoryGap as a percentage", () => {
856
+ it("should increase the gap between bar categories", () => {
857
+ const { container } = render(() => (
858
+ <BarChart width={500} height={300} data={data} barCategoryGap="25%">
859
+ <XAxis dataKey="name" />
860
+ <Bar dataKey="uv" isAnimationActive={false} />
861
+ <Bar dataKey="pv" isAnimationActive={false} />
862
+ </BarChart>
863
+ ));
864
+
865
+ expectBars(container, [
866
+ {
867
+ x: "35.625",
868
+ y: "254.6",
869
+ width: "29",
870
+ height: "10.4",
871
+ radius: "0",
872
+ d: "M 35.625,254.6 h 29 v 10.4 h -29 Z",
873
+ },
874
+ {
875
+ x: "158.125",
876
+ y: "257.2",
877
+ width: "29",
878
+ height: "7.8",
879
+ radius: "0",
880
+ d: "M 158.125,257.2 h 29 v 7.8 h -29 Z",
881
+ },
882
+ {
883
+ x: "280.625",
884
+ y: "257.2",
885
+ width: "29",
886
+ height: "7.8",
887
+ radius: "0",
888
+ d: "M 280.625,257.2 h 29 v 7.8 h -29 Z",
889
+ },
890
+ {
891
+ x: "403.125",
892
+ y: "259.8",
893
+ width: "29",
894
+ height: "5.2",
895
+ radius: "0",
896
+ d: "M 403.125,259.8 h 29 v 5.2 h -29 Z",
897
+ },
898
+ {
899
+ x: "68.625",
900
+ y: "202.6",
901
+ width: "29",
902
+ height: "62.4",
903
+ radius: "0",
904
+ d: "M 68.625,202.6 h 29 v 62.4 h -29 Z",
905
+ },
906
+ {
907
+ x: "191.125",
908
+ y: "146.258",
909
+ width: "29",
910
+ height: "118.742",
911
+ radius: "0",
912
+ d: "M 191.125,146.258 h 29 v 118.742 h -29 Z",
913
+ },
914
+ {
915
+ x: "313.625",
916
+ y: "228.652",
917
+ width: "29",
918
+ height: "36.348",
919
+ radius: "0",
920
+ d: "M 313.625,228.652 h 29 v 36.348 h -29 Z",
921
+ },
922
+ {
923
+ x: "436.125",
924
+ y: "10.2",
925
+ width: "29",
926
+ height: "254.8",
927
+ radius: "0",
928
+ d: "M 436.125,10.2 h 29 v 254.8 h -29 Z",
929
+ },
930
+ ]);
931
+ });
932
+
933
+ it("should decrease the gap between bar categories", () => {
934
+ const { container } = render(() => (
935
+ <BarChart width={500} height={300} data={data} barCategoryGap="3%">
936
+ <XAxis dataKey="name" />
937
+ <Bar dataKey="uv" isAnimationActive={false} />
938
+ <Bar dataKey="pv" isAnimationActive={false} />
939
+ </BarChart>
940
+ ));
941
+
942
+ expectBars(container, [
943
+ {
944
+ x: "8.675",
945
+ y: "254.6",
946
+ width: "56",
947
+ height: "10.4",
948
+ radius: "0",
949
+ d: "M 8.675,254.6 h 56 v 10.4 h -56 Z",
950
+ },
951
+ {
952
+ x: "131.175",
953
+ y: "257.2",
954
+ width: "56",
955
+ height: "7.8",
956
+ radius: "0",
957
+ d: "M 131.175,257.2 h 56 v 7.8 h -56 Z",
958
+ },
959
+ {
960
+ x: "253.675",
961
+ y: "257.2",
962
+ width: "56",
963
+ height: "7.8",
964
+ radius: "0",
965
+ d: "M 253.675,257.2 h 56 v 7.8 h -56 Z",
966
+ },
967
+ {
968
+ x: "376.175",
969
+ y: "259.8",
970
+ width: "56",
971
+ height: "5.2",
972
+ radius: "0",
973
+ d: "M 376.175,259.8 h 56 v 5.2 h -56 Z",
974
+ },
975
+ {
976
+ x: "68.675",
977
+ y: "202.6",
978
+ width: "56",
979
+ height: "62.4",
980
+ radius: "0",
981
+ d: "M 68.675,202.6 h 56 v 62.4 h -56 Z",
982
+ },
983
+ {
984
+ x: "191.175",
985
+ y: "146.258",
986
+ width: "56",
987
+ height: "118.742",
988
+ radius: "0",
989
+ d: "M 191.175,146.258 h 56 v 118.742 h -56 Z",
990
+ },
991
+ {
992
+ x: "313.675",
993
+ y: "228.652",
994
+ width: "56",
995
+ height: "36.348",
996
+ radius: "0",
997
+ d: "M 313.675,228.652 h 56 v 36.348 h -56 Z",
998
+ },
999
+ {
1000
+ x: "436.175",
1001
+ y: "10.2",
1002
+ width: "56",
1003
+ height: "254.8",
1004
+ radius: "0",
1005
+ d: "M 436.175,10.2 h 56 v 254.8 h -56 Z",
1006
+ },
1007
+ ]);
1008
+ });
1009
+ });
1010
+ });
1011
+
1012
+ describe("with margin bigger than width and height", () => {
1013
+ // guard against negative values in clipPath - ref https://github.com/recharts/recharts/issues/2009
1014
+ const renderTestCase = createSelectorTestCase((props) => (
1015
+ <BarChart
1016
+ width={50}
1017
+ height={50}
1018
+ data={data}
1019
+ margin={{
1020
+ top: 50,
1021
+ right: 100,
1022
+ left: 100,
1023
+ bottom: 50,
1024
+ }}
1025
+ >
1026
+ <XAxis type="number" />
1027
+ <YAxis dataKey="name" type="category" />
1028
+ <Bar dataKey="uv" isAnimationActive={false} />
1029
+ {props.children}
1030
+ </BarChart>
1031
+ ));
1032
+
1033
+ it("should return offset", () => {
1034
+ const { spy } = renderTestCase(useOffset);
1035
+ expectLastCalledWith(spy, {
1036
+ bottom: 80,
1037
+ left: 160,
1038
+ right: 100,
1039
+ top: 50,
1040
+ });
1041
+ });
1042
+
1043
+ it("should return plot area", () => {
1044
+ const { spy } = renderTestCase(usePlotArea);
1045
+ expectLastCalledWith(spy, {
1046
+ height: 0,
1047
+ width: 0,
1048
+ x: 160,
1049
+ y: 50,
1050
+ });
1051
+ });
1052
+
1053
+ it("should return internal offset", () => {
1054
+ const { spy } = renderTestCase(useOffsetInternal);
1055
+ expectLastCalledWith(spy, {
1056
+ bottom: 80,
1057
+ brushBottom: 80,
1058
+ height: 0,
1059
+ left: 160,
1060
+ right: 100,
1061
+ top: 50,
1062
+ width: 0,
1063
+ });
1064
+ });
1065
+
1066
+ test("Renders a chart with less width than left, right margin and less height than top, bottom margin", () => {
1067
+ const { container } = renderTestCase();
1068
+
1069
+ // expect nothing to render because height and width are 0
1070
+ expect(container.querySelectorAll(".recharts-rectangle")).toHaveLength(0);
1071
+
1072
+ const clipPath = container.querySelector("defs clipPath");
1073
+ assertNotNull(clipPath);
1074
+ expect(clipPath.children[0]).not.toBeNull();
1075
+
1076
+ // expect clipPath rect to have a width and height of 0
1077
+ expect(clipPath.children[0]).toHaveAttribute("width", "0");
1078
+ expect(clipPath.children[0]).toHaveAttribute("height", "0");
1079
+
1080
+ expectBars(container, []);
1081
+ });
1082
+ });
1083
+
1084
+ test("renders chart when wrapped in a custom component", () => {
1085
+ const MyBarChart = (props: BarChartProps) => {
1086
+ return <BarChart {...props} />;
1087
+ };
1088
+
1089
+ const { container } = render(() => (
1090
+ <MyBarChart width={500} height={300} data={data}>
1091
+ <XAxis dataKey="name" />
1092
+ <YAxis />
1093
+ <Bar dataKey="uv" fill="#8884d8" isAnimationActive={false} />
1094
+ </MyBarChart>
1095
+ ));
1096
+
1097
+ expectBars(container, [
1098
+ {
1099
+ d: "M 75.75,5 h 86 v 260 h -86 Z",
1100
+ height: "260",
1101
+ radius: "0",
1102
+ width: "86",
1103
+ x: "75.75",
1104
+ y: "5",
1105
+ },
1106
+ {
1107
+ d: "M 183.25,70 h 86 v 195 h -86 Z",
1108
+ height: "195",
1109
+ radius: "0",
1110
+ width: "86",
1111
+ x: "183.25",
1112
+ y: "70",
1113
+ },
1114
+ {
1115
+ d: "M 290.75,70 h 86 v 195 h -86 Z",
1116
+ height: "195",
1117
+ radius: "0",
1118
+ width: "86",
1119
+ x: "290.75",
1120
+ y: "70",
1121
+ },
1122
+ {
1123
+ d: "M 398.25,135 h 86 v 130 h -86 Z",
1124
+ height: "130",
1125
+ radius: "0",
1126
+ width: "86",
1127
+ x: "398.25",
1128
+ y: "135",
1129
+ },
1130
+ ]);
1131
+ });
1132
+
1133
+ describe("bar width", () => {
1134
+ it("renders one bar with a width for each data entry", () => {
1135
+ const data2 = [
1136
+ { x: 10, y: 10 },
1137
+ { x: 20, y: 20 },
1138
+ ];
1139
+ const { container } = render(() => (
1140
+ <BarChart width={100} height={50} data={data2}>
1141
+ <Bar dataKey="y" fill="#ff7300" isAnimationActive={false} />
1142
+ <XAxis dataKey="x" />
1143
+ </BarChart>
1144
+ ));
1145
+
1146
+ expectBars(container, [
1147
+ {
1148
+ d: "M 9.5,10 h 36 v 5 h -36 Z",
1149
+ height: "5",
1150
+ radius: "0",
1151
+ width: "36",
1152
+ x: "9.5",
1153
+ y: "10",
1154
+ },
1155
+ {
1156
+ d: "M 54.5,5 h 36 v 10 h -36 Z",
1157
+ height: "10",
1158
+ radius: "0",
1159
+ width: "36",
1160
+ x: "54.5",
1161
+ y: "5",
1162
+ },
1163
+ ]);
1164
+ });
1165
+
1166
+ it("renders one bar with a width for each data entry where two entries have duplicate XAxis coordinate", () => {
1167
+ const data2 = [
1168
+ { x: 10, y: 10 },
1169
+ { x: 10, y: 20 },
1170
+ ];
1171
+ const { container } = render(() => (
1172
+ <BarChart width={100} height={50} data={data2}>
1173
+ <Bar dataKey="y" fill="#ff7300" isAnimationActive={false} />
1174
+ <XAxis dataKey="x" />
1175
+ </BarChart>
1176
+ ));
1177
+
1178
+ expectBars(container, [
1179
+ {
1180
+ d: "M 9.5,10 h 36 v 5 h -36 Z",
1181
+ height: "5",
1182
+ radius: "0",
1183
+ width: "36",
1184
+ x: "9.5",
1185
+ y: "10",
1186
+ },
1187
+ {
1188
+ d: "M 54.5,5 h 36 v 10 h -36 Z",
1189
+ height: "10",
1190
+ radius: "0",
1191
+ width: "36",
1192
+ x: "54.5",
1193
+ y: "5",
1194
+ },
1195
+ ]);
1196
+ });
1197
+
1198
+ it("renders bars where two entries right next to each other have duplicate XAxis coordinate and type=number", () => {
1199
+ const data2 = [
1200
+ { x: 10, y: 10 },
1201
+ { x: 10, y: 20 },
1202
+ ];
1203
+ const { container } = render(() => (
1204
+ <BarChart width={100} height={50} data={data2}>
1205
+ <Bar dataKey="y" fill="#ff7300" isAnimationActive={false} />
1206
+ <XAxis dataKey="x" />
1207
+ </BarChart>
1208
+ ));
1209
+
1210
+ expectBars(container, [
1211
+ {
1212
+ d: "M 9.5,10 h 36 v 5 h -36 Z",
1213
+ height: "5",
1214
+ radius: "0",
1215
+ width: "36",
1216
+ x: "9.5",
1217
+ y: "10",
1218
+ },
1219
+ {
1220
+ d: "M 54.5,5 h 36 v 10 h -36 Z",
1221
+ height: "10",
1222
+ radius: "0",
1223
+ width: "36",
1224
+ x: "54.5",
1225
+ y: "5",
1226
+ },
1227
+ ]);
1228
+ });
1229
+ });
1230
+
1231
+ describe("in horizontal chart", () => {
1232
+ describe("renders overlapping bars when there are separate XAxis", () => {
1233
+ const renderTestCase = createSelectorTestCase((props) => (
1234
+ <BarChart width={800} height={400} data={data}>
1235
+ <Bar
1236
+ dataKey="uv"
1237
+ fill="green"
1238
+ xAxisId="one"
1239
+ barSize={50}
1240
+ isAnimationActive={false}
1241
+ id="bar-axis-one"
1242
+ />
1243
+ <XAxis xAxisId="one" />
1244
+ {/* The smaller bar must be rendered in front of the larger one to be visible. */}
1245
+ <Bar
1246
+ dataKey="pv"
1247
+ fill="red"
1248
+ xAxisId="two"
1249
+ barSize={30}
1250
+ isAnimationActive={false}
1251
+ id="bar-axis-two"
1252
+ />
1253
+ <XAxis xAxisId="two" hide />
1254
+
1255
+ {props.children}
1256
+ </BarChart>
1257
+ ));
1258
+
1259
+ test("selectUnfilteredCartesianItems", () => {
1260
+ const { spy } = renderTestCase(selectUnfilteredCartesianItems);
1261
+ const expected: ReadonlyArray<BarSettings> = [
1262
+ {
1263
+ id: "bar-axis-one",
1264
+ isPanorama: false,
1265
+ barSize: 50,
1266
+ data: undefined,
1267
+ dataKey: "uv",
1268
+ hide: false,
1269
+ stackId: undefined,
1270
+ type: "bar",
1271
+ xAxisId: "one",
1272
+ yAxisId: 0,
1273
+ zAxisId: 0,
1274
+ maxBarSize: undefined,
1275
+ minPointSize: 0,
1276
+ hasCustomShape: false,
1277
+ },
1278
+ {
1279
+ id: "bar-axis-two",
1280
+ isPanorama: false,
1281
+ barSize: 30,
1282
+ data: undefined,
1283
+ dataKey: "pv",
1284
+ hide: false,
1285
+ stackId: undefined,
1286
+ type: "bar",
1287
+ xAxisId: "two",
1288
+ yAxisId: 0,
1289
+ zAxisId: 0,
1290
+ maxBarSize: undefined,
1291
+ minPointSize: 0,
1292
+ hasCustomShape: false,
1293
+ },
1294
+ ];
1295
+ expectLastCalledWith(spy, expected);
1296
+ });
1297
+
1298
+ it("should select bars for first axis", () => {
1299
+ const { spy } = renderTestCase((state) => selectAllVisibleBars(state, "bar-axis-one", false));
1300
+ expectLastCalledWith(spy, [
1301
+ {
1302
+ id: "bar-axis-one",
1303
+ isPanorama: false,
1304
+ maxBarSize: undefined,
1305
+ minPointSize: 0,
1306
+ hasCustomShape: false,
1307
+ barSize: 50,
1308
+ data: undefined,
1309
+ dataKey: "uv",
1310
+ hide: false,
1311
+ stackId: undefined,
1312
+ type: "bar",
1313
+ xAxisId: "one",
1314
+ yAxisId: 0,
1315
+ zAxisId: 0,
1316
+ },
1317
+ ]);
1318
+ });
1319
+
1320
+ it("should select bars for second axis", () => {
1321
+ const { spy } = renderTestCase((state) => selectAllVisibleBars(state, "bar-axis-two", false));
1322
+ expectLastCalledWith(spy, [
1323
+ {
1324
+ id: "bar-axis-two",
1325
+ isPanorama: false,
1326
+ maxBarSize: undefined,
1327
+ minPointSize: 0,
1328
+ hasCustomShape: false,
1329
+ barSize: 30,
1330
+ data: undefined,
1331
+ dataKey: "pv",
1332
+ hide: false,
1333
+ stackId: undefined,
1334
+ type: "bar",
1335
+ xAxisId: "two",
1336
+ yAxisId: 0,
1337
+ zAxisId: 0,
1338
+ },
1339
+ ]);
1340
+ });
1341
+
1342
+ it("should render bars", () => {
1343
+ const { container } = renderTestCase();
1344
+ expectBars(container, [
1345
+ {
1346
+ x: "79",
1347
+ y: "350.6",
1348
+ width: "50",
1349
+ height: "14.4",
1350
+ radius: "0",
1351
+ d: "M 79,350.6 h 50 v 14.4 h -50 Z",
1352
+ },
1353
+ {
1354
+ x: "276.5",
1355
+ y: "354.2",
1356
+ width: "50",
1357
+ height: "10.8",
1358
+ radius: "0",
1359
+ d: "M 276.5,354.2 h 50 v 10.8 h -50 Z",
1360
+ },
1361
+ {
1362
+ x: "474",
1363
+ y: "354.2",
1364
+ width: "50",
1365
+ height: "10.8",
1366
+ radius: "0",
1367
+ d: "M 474,354.2 h 50 v 10.8 h -50 Z",
1368
+ },
1369
+ {
1370
+ x: "671.5",
1371
+ y: "357.8",
1372
+ width: "50",
1373
+ height: "7.2",
1374
+ radius: "0",
1375
+ d: "M 671.5,357.8 h 50 v 7.2 h -50 Z",
1376
+ },
1377
+ {
1378
+ x: "89",
1379
+ y: "278.6",
1380
+ width: "30",
1381
+ height: "86.4",
1382
+ radius: "0",
1383
+ d: "M 89,278.6 h 30 v 86.4 h -30 Z",
1384
+ },
1385
+ {
1386
+ x: "286.5",
1387
+ y: "200.588",
1388
+ width: "30",
1389
+ height: "164.412",
1390
+ radius: "0",
1391
+ d: "M 286.5,200.588 h 30 v 164.412 h -30 Z",
1392
+ },
1393
+ {
1394
+ x: "484",
1395
+ y: "314.672",
1396
+ width: "30",
1397
+ height: "50.328",
1398
+ radius: "0",
1399
+ d: "M 484,314.672 h 30 v 50.328 h -30 Z",
1400
+ },
1401
+ {
1402
+ x: "681.5",
1403
+ y: "12.2",
1404
+ width: "30",
1405
+ height: "352.8",
1406
+ radius: "0",
1407
+ d: "M 681.5,12.2 h 30 v 352.8 h -30 Z",
1408
+ },
1409
+ ]);
1410
+ });
1411
+ });
1412
+
1413
+ describe("renders bars as neighbours when there are multiple YAxes", () => {
1414
+ const renderTestCase = createSelectorTestCase((props) => (
1415
+ <BarChart width={500} height={300} data={data}>
1416
+ <XAxis dataKey="name" />
1417
+ <YAxis yAxisId="left" orientation="left" />
1418
+ <YAxis yAxisId="right" orientation="right" />
1419
+ <Bar yAxisId="left" id="my-bar-id-1" dataKey="pv" isAnimationActive={false} />
1420
+ <Bar yAxisId="right" id="my-bar-id-2" dataKey="uv" isAnimationActive={false} />
1421
+ {props.children}
1422
+ </BarChart>
1423
+ ));
1424
+
1425
+ test("selectUnfilteredCartesianItems", () => {
1426
+ const { spy } = renderTestCase(selectUnfilteredCartesianItems);
1427
+ const expected: ReadonlyArray<CartesianGraphicalItemSettings> = [
1428
+ {
1429
+ id: "my-bar-id-1",
1430
+ isPanorama: false,
1431
+ maxBarSize: undefined,
1432
+ minPointSize: 0,
1433
+ hasCustomShape: false,
1434
+ barSize: undefined,
1435
+ data: undefined,
1436
+ dataKey: "pv",
1437
+ hide: false,
1438
+ stackId: undefined,
1439
+ type: "bar",
1440
+ xAxisId: 0,
1441
+ yAxisId: "left",
1442
+ zAxisId: 0,
1443
+ },
1444
+ {
1445
+ id: "my-bar-id-2",
1446
+ isPanorama: false,
1447
+ maxBarSize: undefined,
1448
+ minPointSize: 0,
1449
+ hasCustomShape: false,
1450
+ barSize: undefined,
1451
+ data: undefined,
1452
+ dataKey: "uv",
1453
+ hide: false,
1454
+ stackId: undefined,
1455
+ type: "bar",
1456
+ xAxisId: 0,
1457
+ yAxisId: "right",
1458
+ zAxisId: 0,
1459
+ },
1460
+ ];
1461
+ expectLastCalledWith(spy, expected);
1462
+ });
1463
+
1464
+ it("should select bars for left axis", () => {
1465
+ const { spy } = renderTestCase((state) => selectAllVisibleBars(state, "my-bar-id-1", false));
1466
+ expectLastCalledWith(spy, [
1467
+ {
1468
+ id: "my-bar-id-1",
1469
+ isPanorama: false,
1470
+ maxBarSize: undefined,
1471
+ minPointSize: 0,
1472
+ hasCustomShape: false,
1473
+ barSize: undefined,
1474
+ data: undefined,
1475
+ dataKey: "pv",
1476
+ hide: false,
1477
+ stackId: undefined,
1478
+ type: "bar",
1479
+ xAxisId: 0,
1480
+ yAxisId: "left",
1481
+ zAxisId: 0,
1482
+ },
1483
+ {
1484
+ id: "my-bar-id-2",
1485
+ isPanorama: false,
1486
+ maxBarSize: undefined,
1487
+ minPointSize: 0,
1488
+ hasCustomShape: false,
1489
+ barSize: undefined,
1490
+ data: undefined,
1491
+ dataKey: "uv",
1492
+ hide: false,
1493
+ stackId: undefined,
1494
+ type: "bar",
1495
+ xAxisId: 0,
1496
+ // this one quite clearly belongs to the right axis, why is it returned here?
1497
+ yAxisId: "right",
1498
+ zAxisId: 0,
1499
+ },
1500
+ ]);
1501
+ });
1502
+
1503
+ it("should select bars for right axis", () => {
1504
+ const { spy } = renderTestCase((state) => selectAllVisibleBars(state, "my-bar-id-2", false));
1505
+ expectLastCalledWith(spy, [
1506
+ {
1507
+ id: "my-bar-id-1",
1508
+ isPanorama: false,
1509
+ maxBarSize: undefined,
1510
+ minPointSize: 0,
1511
+ hasCustomShape: false,
1512
+ barSize: undefined,
1513
+ data: undefined,
1514
+ dataKey: "pv",
1515
+ hide: false,
1516
+ stackId: undefined,
1517
+ type: "bar",
1518
+ xAxisId: 0,
1519
+ // this one quite clearly belongs to the left axis, why is it returned here?
1520
+ yAxisId: "left",
1521
+ zAxisId: 0,
1522
+ },
1523
+ {
1524
+ id: "my-bar-id-2",
1525
+ isPanorama: false,
1526
+ maxBarSize: undefined,
1527
+ minPointSize: 0,
1528
+ hasCustomShape: false,
1529
+ barSize: undefined,
1530
+ data: undefined,
1531
+ dataKey: "uv",
1532
+ hide: false,
1533
+ stackId: undefined,
1534
+ type: "bar",
1535
+ xAxisId: 0,
1536
+ yAxisId: "right",
1537
+ zAxisId: 0,
1538
+ },
1539
+ ]);
1540
+ });
1541
+
1542
+ it("should select bar size list for left axis", () => {
1543
+ const { spy } = renderTestCase((state) => selectBarSizeList(state, "my-bar-id-1", false));
1544
+ expectLastCalledWith(spy, [
1545
+ {
1546
+ barSize: undefined,
1547
+ dataKeys: ["pv"],
1548
+ stackId: undefined,
1549
+ },
1550
+ {
1551
+ barSize: undefined,
1552
+ dataKeys: ["uv"],
1553
+ stackId: undefined,
1554
+ },
1555
+ ]);
1556
+ });
1557
+
1558
+ it("should select bar size list for right axis", () => {
1559
+ const { spy } = renderTestCase((state) => selectBarSizeList(state, "my-bar-id-2", false));
1560
+ expectLastCalledWith(spy, [
1561
+ {
1562
+ barSize: undefined,
1563
+ dataKeys: ["pv"],
1564
+ stackId: undefined,
1565
+ },
1566
+ {
1567
+ barSize: undefined,
1568
+ dataKeys: ["uv"],
1569
+ stackId: undefined,
1570
+ },
1571
+ ]);
1572
+ });
1573
+
1574
+ it("should select all bar positions for left axis", () => {
1575
+ const { spy } = renderTestCase((state) => selectAllBarPositions(state, "my-bar-id-1", false));
1576
+ expectLastCalledWith(spy, [
1577
+ {
1578
+ dataKeys: ["pv"],
1579
+ position: {
1580
+ offset: 9.25,
1581
+ size: 35,
1582
+ },
1583
+ stackId: undefined,
1584
+ },
1585
+ {
1586
+ dataKeys: ["uv"],
1587
+ position: {
1588
+ offset: 48.25,
1589
+ size: 35,
1590
+ },
1591
+ stackId: undefined,
1592
+ },
1593
+ ]);
1594
+ });
1595
+
1596
+ it("should select all bar positions for right axis", () => {
1597
+ const { spy } = renderTestCase((state) => selectAllBarPositions(state, "my-bar-id-2", false));
1598
+ expectLastCalledWith(spy, [
1599
+ {
1600
+ dataKeys: ["pv"],
1601
+ position: {
1602
+ offset: 9.25,
1603
+ size: 35,
1604
+ },
1605
+ stackId: undefined,
1606
+ },
1607
+ {
1608
+ dataKeys: ["uv"],
1609
+ position: {
1610
+ offset: 48.25,
1611
+ size: 35,
1612
+ },
1613
+ stackId: undefined,
1614
+ },
1615
+ ]);
1616
+ });
1617
+
1618
+ it("should render bars", () => {
1619
+ const { container } = renderTestCase();
1620
+
1621
+ expectBars(container, [
1622
+ {
1623
+ d: "M 74.25,202.6 h 35 v 62.4 h -35 Z",
1624
+ height: "62.4",
1625
+ radius: "0",
1626
+ width: "35",
1627
+ x: "74.25",
1628
+ y: "202.6",
1629
+ },
1630
+ {
1631
+ d: "M 166.75,146.258 h 35 v 118.742 h -35 Z",
1632
+ height: "118.742",
1633
+ radius: "0",
1634
+ width: "35",
1635
+ x: "166.75",
1636
+ y: "146.258",
1637
+ },
1638
+ {
1639
+ d: "M 259.25,228.652 h 35 v 36.348 h -35 Z",
1640
+ height: "36.348",
1641
+ radius: "0",
1642
+ width: "35",
1643
+ x: "259.25",
1644
+ y: "228.652",
1645
+ },
1646
+ {
1647
+ d: "M 351.75,10.2 h 35 v 254.8 h -35 Z",
1648
+ height: "254.8",
1649
+ radius: "0",
1650
+ width: "35",
1651
+ x: "351.75",
1652
+ y: "10.2",
1653
+ },
1654
+ {
1655
+ d: "M 113.25,5 h 35 v 260 h -35 Z",
1656
+ height: "260",
1657
+ radius: "0",
1658
+ width: "35",
1659
+ x: "113.25",
1660
+ y: "5",
1661
+ },
1662
+ {
1663
+ d: "M 205.75,70 h 35 v 195 h -35 Z",
1664
+ height: "195",
1665
+ radius: "0",
1666
+ width: "35",
1667
+ x: "205.75",
1668
+ y: "70",
1669
+ },
1670
+ {
1671
+ d: "M 298.25,70 h 35 v 195 h -35 Z",
1672
+ height: "195",
1673
+ radius: "0",
1674
+ width: "35",
1675
+ x: "298.25",
1676
+ y: "70",
1677
+ },
1678
+ {
1679
+ d: "M 390.75,135 h 35 v 130 h -35 Z",
1680
+ height: "130",
1681
+ radius: "0",
1682
+ width: "35",
1683
+ x: "390.75",
1684
+ y: "135",
1685
+ },
1686
+ ]);
1687
+ });
1688
+ });
1689
+ });
1690
+
1691
+ describe("in vertical chart", () => {
1692
+ describe("renders bars as neighbours when there are multiple XAxes", () => {
1693
+ const renderTestCase = createSelectorTestCase((props) => (
1694
+ <BarChart width={300} height={300} data={data} layout="vertical">
1695
+ <Bar
1696
+ dataKey="uv"
1697
+ xAxisId={2}
1698
+ fill="blue"
1699
+ barSize={40}
1700
+ isAnimationActive={false}
1701
+ id="bar-xaxis-2"
1702
+ />
1703
+ <Bar
1704
+ dataKey="pv"
1705
+ xAxisId={1}
1706
+ fill="green"
1707
+ barSize={30}
1708
+ isAnimationActive={false}
1709
+ id="bar-xaxis-1"
1710
+ />
1711
+ <XAxis xAxisId={1} type="number" />
1712
+ <XAxis xAxisId={2} type="number" orientation="top" />
1713
+ <YAxis type="category" />
1714
+ {props.children}
1715
+ </BarChart>
1716
+ ));
1717
+
1718
+ test("selectUnfilteredCartesianItems", () => {
1719
+ const { spy } = renderTestCase(selectUnfilteredCartesianItems);
1720
+ const expected: ReadonlyArray<CartesianGraphicalItemSettings> = [
1721
+ {
1722
+ id: "bar-xaxis-2",
1723
+ isPanorama: false,
1724
+ maxBarSize: undefined,
1725
+ minPointSize: 0,
1726
+ hasCustomShape: false,
1727
+ barSize: 40,
1728
+ data: undefined,
1729
+ dataKey: "uv",
1730
+ hide: false,
1731
+ stackId: undefined,
1732
+ type: "bar",
1733
+ xAxisId: 2,
1734
+ yAxisId: 0,
1735
+ zAxisId: 0,
1736
+ },
1737
+ {
1738
+ id: "bar-xaxis-1",
1739
+ isPanorama: false,
1740
+ maxBarSize: undefined,
1741
+ minPointSize: 0,
1742
+ hasCustomShape: false,
1743
+ barSize: 30,
1744
+ data: undefined,
1745
+ dataKey: "pv",
1746
+ hide: false,
1747
+ stackId: undefined,
1748
+ type: "bar",
1749
+ xAxisId: 1,
1750
+ yAxisId: 0,
1751
+ zAxisId: 0,
1752
+ },
1753
+ ];
1754
+ expectLastCalledWith(spy, expected);
1755
+ });
1756
+
1757
+ it("should select bars for first axis", () => {
1758
+ const { spy } = renderTestCase((state) => selectAllVisibleBars(state, "bar-xaxis-2", false));
1759
+ expectLastCalledWith(spy, [
1760
+ {
1761
+ id: "bar-xaxis-2",
1762
+ isPanorama: false,
1763
+ maxBarSize: undefined,
1764
+ minPointSize: 0,
1765
+ hasCustomShape: false,
1766
+ barSize: 40,
1767
+ data: undefined,
1768
+ dataKey: "uv",
1769
+ hide: false,
1770
+ stackId: undefined,
1771
+ type: "bar",
1772
+ xAxisId: 2,
1773
+ yAxisId: 0,
1774
+ zAxisId: 0,
1775
+ },
1776
+ {
1777
+ id: "bar-xaxis-1",
1778
+ isPanorama: false,
1779
+ maxBarSize: undefined,
1780
+ minPointSize: 0,
1781
+ hasCustomShape: false,
1782
+ barSize: 30,
1783
+ data: undefined,
1784
+ dataKey: "pv",
1785
+ hide: false,
1786
+ stackId: undefined,
1787
+ type: "bar",
1788
+ // this one quite clearly belongs to the second axis, why is it returned here?
1789
+ xAxisId: 1,
1790
+ yAxisId: 0,
1791
+ zAxisId: 0,
1792
+ },
1793
+ ]);
1794
+ });
1795
+
1796
+ it("should select bars for second axis", () => {
1797
+ const { spy } = renderTestCase((state) => selectAllVisibleBars(state, "bar-xaxis-1", false));
1798
+ expectLastCalledWith(spy, [
1799
+ {
1800
+ id: "bar-xaxis-2",
1801
+ isPanorama: false,
1802
+ maxBarSize: undefined,
1803
+ minPointSize: 0,
1804
+ hasCustomShape: false,
1805
+ barSize: 40,
1806
+ data: undefined,
1807
+ dataKey: "uv",
1808
+ hide: false,
1809
+ stackId: undefined,
1810
+ type: "bar",
1811
+ // this one quite clearly belongs to the first axis, why is it returned here?
1812
+ xAxisId: 2,
1813
+ yAxisId: 0,
1814
+ zAxisId: 0,
1815
+ },
1816
+ {
1817
+ id: "bar-xaxis-1",
1818
+ isPanorama: false,
1819
+ maxBarSize: undefined,
1820
+ minPointSize: 0,
1821
+ hasCustomShape: false,
1822
+ barSize: 30,
1823
+ data: undefined,
1824
+ dataKey: "pv",
1825
+ hide: false,
1826
+ stackId: undefined,
1827
+ type: "bar",
1828
+ xAxisId: 1,
1829
+ yAxisId: 0,
1830
+ zAxisId: 0,
1831
+ },
1832
+ ]);
1833
+ });
1834
+
1835
+ it("should render bars", () => {
1836
+ const { container } = renderTestCase();
1837
+
1838
+ expectBars(container, [
1839
+ {
1840
+ x: "65",
1841
+ y: "38",
1842
+ width: "230",
1843
+ height: "25.875",
1844
+ radius: "0",
1845
+ d: "M 65,38 h 230 v 25.875 h -230 Z",
1846
+ },
1847
+ {
1848
+ x: "65",
1849
+ y: "95.5",
1850
+ width: "172.5",
1851
+ height: "25.875",
1852
+ radius: "0",
1853
+ d: "M 65,95.5 h 172.5 v 25.875 h -172.5 Z",
1854
+ },
1855
+ {
1856
+ x: "65",
1857
+ y: "153",
1858
+ width: "172.5",
1859
+ height: "25.875",
1860
+ radius: "0",
1861
+ d: "M 65,153 h 172.5 v 25.875 h -172.5 Z",
1862
+ },
1863
+ {
1864
+ x: "65",
1865
+ y: "210.5",
1866
+ width: "115",
1867
+ height: "25.875",
1868
+ radius: "0",
1869
+ d: "M 65,210.5 h 115 v 25.875 h -115 Z",
1870
+ },
1871
+ {
1872
+ x: "65",
1873
+ y: "63.875",
1874
+ width: "55.2",
1875
+ height: "25.875",
1876
+ radius: "0",
1877
+ d: "M 65,63.875 h 55.2 v 25.875 h -55.2 Z",
1878
+ },
1879
+ {
1880
+ x: "65",
1881
+ y: "121.375",
1882
+ width: "105.041",
1883
+ height: "25.875",
1884
+ radius: "0",
1885
+ d: "M 65,121.375 h 105.041 v 25.875 h -105.041 Z",
1886
+ },
1887
+ {
1888
+ x: "65",
1889
+ y: "178.875",
1890
+ width: "32.154",
1891
+ height: "25.875",
1892
+ radius: "0",
1893
+ d: "M 65,178.875 h 32.154 v 25.875 h -32.154 Z",
1894
+ },
1895
+ {
1896
+ x: "65",
1897
+ y: "236.375",
1898
+ width: "225.4",
1899
+ height: "25.875",
1900
+ radius: "0",
1901
+ d: "M 65,236.375 h 225.4 v 25.875 h -225.4 Z",
1902
+ },
1903
+ ]);
1904
+ });
1905
+ });
1906
+
1907
+ describe("renders overlapping bars when there are multiple YAxes", () => {
1908
+ const renderTestCase = createSelectorTestCase((props) => (
1909
+ <BarChart width={300} height={300} data={data} layout="vertical">
1910
+ <Bar
1911
+ id="bar-left"
1912
+ dataKey="uv"
1913
+ yAxisId="left"
1914
+ fill="blue"
1915
+ barSize={30}
1916
+ isAnimationActive={false}
1917
+ />
1918
+ <Bar
1919
+ id="bar-right"
1920
+ dataKey="pv"
1921
+ yAxisId="right"
1922
+ fill="green"
1923
+ barSize={20}
1924
+ isAnimationActive={false}
1925
+ />
1926
+ <YAxis yAxisId="left" orientation="left" type="category" />
1927
+ <YAxis yAxisId="right" orientation="right" hide type="category" />
1928
+ <XAxis type="number" />
1929
+ {props.children}
1930
+ </BarChart>
1931
+ ));
1932
+
1933
+ test("selectUnfilteredCartesianItems", () => {
1934
+ const { spy } = renderTestCase(selectUnfilteredCartesianItems);
1935
+ const expected: ReadonlyArray<CartesianGraphicalItemSettings> = [
1936
+ {
1937
+ id: "bar-left",
1938
+ isPanorama: false,
1939
+ maxBarSize: undefined,
1940
+ minPointSize: 0,
1941
+ hasCustomShape: false,
1942
+ barSize: 30,
1943
+ data: undefined,
1944
+ dataKey: "uv",
1945
+ hide: false,
1946
+ stackId: undefined,
1947
+ type: "bar",
1948
+ xAxisId: 0,
1949
+ yAxisId: "left",
1950
+ zAxisId: 0,
1951
+ },
1952
+ {
1953
+ id: "bar-right",
1954
+ isPanorama: false,
1955
+ maxBarSize: undefined,
1956
+ minPointSize: 0,
1957
+ hasCustomShape: false,
1958
+ barSize: 20,
1959
+ data: undefined,
1960
+ dataKey: "pv",
1961
+ hide: false,
1962
+ stackId: undefined,
1963
+ type: "bar",
1964
+ xAxisId: 0,
1965
+ yAxisId: "right",
1966
+ zAxisId: 0,
1967
+ },
1968
+ ];
1969
+ expectLastCalledWith(spy, expected);
1970
+ });
1971
+
1972
+ it("should select bars for left axis", () => {
1973
+ const { spy } = renderTestCase((state) => selectAllVisibleBars(state, "bar-left", false));
1974
+ expectLastCalledWith(spy, [
1975
+ {
1976
+ id: "bar-left",
1977
+ isPanorama: false,
1978
+ maxBarSize: undefined,
1979
+ minPointSize: 0,
1980
+ hasCustomShape: false,
1981
+ barSize: 30,
1982
+ data: undefined,
1983
+ dataKey: "uv",
1984
+ hide: false,
1985
+ stackId: undefined,
1986
+ type: "bar",
1987
+ xAxisId: 0,
1988
+ yAxisId: "left",
1989
+ zAxisId: 0,
1990
+ },
1991
+ ]);
1992
+ });
1993
+
1994
+ it("should select bars for right axis", () => {
1995
+ const { spy } = renderTestCase((state) => selectAllVisibleBars(state, "bar-right", false));
1996
+ expectLastCalledWith(spy, [
1997
+ {
1998
+ id: "bar-right",
1999
+ isPanorama: false,
2000
+ maxBarSize: undefined,
2001
+ minPointSize: 0,
2002
+ hasCustomShape: false,
2003
+ barSize: 20,
2004
+ data: undefined,
2005
+ dataKey: "pv",
2006
+ hide: false,
2007
+ stackId: undefined,
2008
+ type: "bar",
2009
+ xAxisId: 0,
2010
+ yAxisId: "right",
2011
+ zAxisId: 0,
2012
+ },
2013
+ ]);
2014
+ });
2015
+
2016
+ it("should select bar size list for left axis", () => {
2017
+ const { spy } = renderTestCase((state) => selectBarSizeList(state, "bar-left", false));
2018
+ expectLastCalledWith(spy, [
2019
+ {
2020
+ barSize: 30,
2021
+ dataKeys: ["uv"],
2022
+ stackId: undefined,
2023
+ },
2024
+ ]);
2025
+ });
2026
+
2027
+ it("should select bar size list for right axis", () => {
2028
+ const { spy } = renderTestCase((state) => selectBarSizeList(state, "bar-right", false));
2029
+ expectLastCalledWith(spy, [
2030
+ {
2031
+ barSize: 20,
2032
+ dataKeys: ["pv"],
2033
+ stackId: undefined,
2034
+ },
2035
+ ]);
2036
+ });
2037
+
2038
+ it("should select all bar positions for left axis", () => {
2039
+ const { spy } = renderTestCase((state) => selectAllBarPositions(state, "bar-left", false));
2040
+ expectLastCalledWith(spy, [
2041
+ {
2042
+ dataKeys: ["uv"],
2043
+ position: {
2044
+ offset: 18,
2045
+ size: 30,
2046
+ },
2047
+ stackId: undefined,
2048
+ },
2049
+ ]);
2050
+ });
2051
+
2052
+ it("should select all bar positions for right axis", () => {
2053
+ const { spy } = renderTestCase((state) => selectAllBarPositions(state, "bar-right", false));
2054
+ expectLastCalledWith(spy, [
2055
+ {
2056
+ dataKeys: ["pv"],
2057
+ position: {
2058
+ offset: 23,
2059
+ size: 20,
2060
+ },
2061
+ stackId: undefined,
2062
+ },
2063
+ ]);
2064
+ });
2065
+
2066
+ it("should render bars", () => {
2067
+ const { container } = renderTestCase();
2068
+
2069
+ expectBars(container, [
2070
+ {
2071
+ x: "65",
2072
+ y: "23",
2073
+ width: "9.2",
2074
+ height: "30",
2075
+ radius: "0",
2076
+ d: "M 65,23 h 9.2 v 30 h -9.2 Z",
2077
+ },
2078
+ {
2079
+ x: "65",
2080
+ y: "88",
2081
+ width: "6.9",
2082
+ height: "30",
2083
+ radius: "0",
2084
+ d: "M 65,88 h 6.9 v 30 h -6.9 Z",
2085
+ },
2086
+ {
2087
+ x: "65",
2088
+ y: "153",
2089
+ width: "6.9",
2090
+ height: "30",
2091
+ radius: "0",
2092
+ d: "M 65,153 h 6.9 v 30 h -6.9 Z",
2093
+ },
2094
+ {
2095
+ x: "65",
2096
+ y: "218",
2097
+ width: "4.6",
2098
+ height: "30",
2099
+ radius: "0",
2100
+ d: "M 65,218 h 4.6 v 30 h -4.6 Z",
2101
+ },
2102
+ {
2103
+ x: "65",
2104
+ y: "28",
2105
+ width: "55.2",
2106
+ height: "20",
2107
+ radius: "0",
2108
+ d: "M 65,28 h 55.2 v 20 h -55.2 Z",
2109
+ },
2110
+ {
2111
+ x: "65",
2112
+ y: "93",
2113
+ width: "105.041",
2114
+ height: "20",
2115
+ radius: "0",
2116
+ d: "M 65,93 h 105.041 v 20 h -105.041 Z",
2117
+ },
2118
+ {
2119
+ x: "65",
2120
+ y: "158",
2121
+ width: "32.154",
2122
+ height: "20",
2123
+ radius: "0",
2124
+ d: "M 65,158 h 32.154 v 20 h -32.154 Z",
2125
+ },
2126
+ {
2127
+ x: "65",
2128
+ y: "223",
2129
+ width: "225.4",
2130
+ height: "20",
2131
+ radius: "0",
2132
+ d: "M 65,223 h 225.4 v 20 h -225.4 Z",
2133
+ },
2134
+ ]);
2135
+ });
2136
+ });
2137
+ });
2138
+
2139
+ describe("stacked bar chart when x-axis is of type number and layout is vertical", () => {
2140
+ const dataWithNumberAsKey = [
2141
+ { xKey: 4000, uv: 400, pv: 2400 },
2142
+ { xKey: 6000, uv: 300, pv: 4567 },
2143
+ { xKey: 8000, uv: 300, pv: 1398 },
2144
+ { xKey: 10000, uv: 200, pv: 9800 },
2145
+ ];
2146
+
2147
+ const renderTestCase = createSelectorTestCase((props) => (
2148
+ <BarChart width={500} height={400} data={dataWithNumberAsKey} layout="vertical">
2149
+ <XAxis type="number" dataKey="xKey" domain={["dataMin", "dataMax"]} />
2150
+ <Bar dataKey="uv" stackId="test" fill="#ff7300" isAnimationActive={false} id="my-bar-id" />
2151
+ <Bar dataKey="pv" stackId="test" fill="#387908" isAnimationActive={false} />
2152
+ {props.children}
2153
+ </BarChart>
2154
+ ));
2155
+
2156
+ test("selectCategoricalDomain", () => {
2157
+ const { spy } = renderTestCase((state) =>
2158
+ selectCategoricalDomain(state, "yAxis", defaultAxisId, false),
2159
+ );
2160
+ expectLastCalledWith(spy, undefined);
2161
+ });
2162
+
2163
+ test("selectBarSizeList", () => {
2164
+ const { spy } = renderTestCase((state) => selectBarSizeList(state, "my-bar-id", false));
2165
+ expectLastCalledWith(spy, [
2166
+ {
2167
+ barSize: undefined,
2168
+ dataKeys: ["uv", "pv"],
2169
+ stackId: "test",
2170
+ },
2171
+ ]);
2172
+ });
2173
+
2174
+ test("selectAxisScale", () => {
2175
+ const { spy } = renderTestCase((state) =>
2176
+ selectAxisScale(state, "yAxis", defaultAxisId, false),
2177
+ );
2178
+ // The port has no `toBeRechartsScale` matcher; assert domain/range directly.
2179
+ expectScale(spy.mock.lastCall?.[0], { domain: [0, 3], range: [5, 365] });
2180
+ });
2181
+
2182
+ test("selectTicksOfGraphicalItem", () => {
2183
+ const { spy } = renderTestCase((state) =>
2184
+ selectTicksOfGraphicalItem(state, "yAxis", defaultAxisId, false),
2185
+ );
2186
+ expectLastCalledWith(spy, [
2187
+ {
2188
+ coordinate: 5,
2189
+ index: 0,
2190
+ offset: 0,
2191
+ value: 0,
2192
+ },
2193
+ {
2194
+ coordinate: 65,
2195
+ index: 1,
2196
+ offset: 0,
2197
+ value: 0.5,
2198
+ },
2199
+ {
2200
+ coordinate: 124.99999999999999,
2201
+ index: 2,
2202
+ offset: 0,
2203
+ value: 1,
2204
+ },
2205
+ {
2206
+ coordinate: 185,
2207
+ index: 3,
2208
+ offset: 0,
2209
+ value: 1.5,
2210
+ },
2211
+ {
2212
+ coordinate: 244.99999999999997,
2213
+ index: 4,
2214
+ offset: 0,
2215
+ value: 2,
2216
+ },
2217
+ {
2218
+ coordinate: 305,
2219
+ index: 5,
2220
+ offset: 0,
2221
+ value: 2.5,
2222
+ },
2223
+ {
2224
+ coordinate: 365,
2225
+ index: 6,
2226
+ offset: 0,
2227
+ value: 3,
2228
+ },
2229
+ ]);
2230
+ });
2231
+
2232
+ test("selectBarBandSize", () => {
2233
+ const { spy } = renderTestCase((state) => selectBarBandSize(state, "my-bar-id", false));
2234
+ expectLastCalledWith(spy, 59.99999999999997);
2235
+ });
2236
+
2237
+ test("selectAllBarPositions", () => {
2238
+ const { spy } = renderTestCase((state) => selectAllBarPositions(state, "my-bar-id", false));
2239
+ expectLastCalledWith(spy, [
2240
+ {
2241
+ stackId: "test",
2242
+ dataKeys: ["uv", "pv"],
2243
+ position: {
2244
+ offset: 5.999999999999997,
2245
+ size: 48,
2246
+ },
2247
+ },
2248
+ ]);
2249
+ });
2250
+
2251
+ test("selectBarPosition", () => {
2252
+ const { spy } = renderTestCase((state) => selectBarPosition(state, "my-bar-id", false));
2253
+ expectLastCalledWith(spy, {
2254
+ offset: 5.999999999999997,
2255
+ size: 48,
2256
+ });
2257
+ });
2258
+
2259
+ test("selectBarRectangles", () => {
2260
+ const { spy } = renderTestCase((state) =>
2261
+ selectBarRectangles(state, "my-bar-id", false, undefined),
2262
+ );
2263
+ expectLastCalledWith(spy, [
2264
+ {
2265
+ xKey: 4000,
2266
+ uv: 400,
2267
+ pv: 2400,
2268
+ stackedBarStart: 5,
2269
+ x: 5,
2270
+ y: -18.99999999999999,
2271
+ width: 19.6,
2272
+ height: 48,
2273
+ value: [0, 400],
2274
+ payload: {
2275
+ xKey: 4000,
2276
+ uv: 400,
2277
+ pv: 2400,
2278
+ },
2279
+ background: {
2280
+ x: 5,
2281
+ y: -18.99999999999999,
2282
+ width: 490,
2283
+ height: 48,
2284
+ },
2285
+ tooltipPosition: {
2286
+ x: 14.8,
2287
+ y: 5.000000000000011,
2288
+ },
2289
+ parentViewBox: {
2290
+ x: 0,
2291
+ y: 0,
2292
+ width: 500,
2293
+ height: 400,
2294
+ },
2295
+ originalDataIndex: 0,
2296
+ },
2297
+ {
2298
+ xKey: 6000,
2299
+ uv: 300,
2300
+ pv: 4567,
2301
+ stackedBarStart: 5,
2302
+ x: 5,
2303
+ y: 341,
2304
+ width: 14.7,
2305
+ height: 48,
2306
+ value: [0, 300],
2307
+ payload: {
2308
+ xKey: 6000,
2309
+ uv: 300,
2310
+ pv: 4567,
2311
+ },
2312
+ background: {
2313
+ x: 5,
2314
+ y: 341,
2315
+ width: 490,
2316
+ height: 48,
2317
+ },
2318
+ tooltipPosition: {
2319
+ x: 12.35,
2320
+ y: 365,
2321
+ },
2322
+ parentViewBox: {
2323
+ x: 0,
2324
+ y: 0,
2325
+ width: 500,
2326
+ height: 400,
2327
+ },
2328
+ originalDataIndex: 1,
2329
+ },
2330
+ ] as unknown as BarRectangleItem[]);
2331
+ });
2332
+
2333
+ it("should render bars", () => {
2334
+ const { container } = renderTestCase();
2335
+ expectBars(container, [
2336
+ {
2337
+ x: "5",
2338
+ y: "-19",
2339
+ width: "19.6",
2340
+ height: "48",
2341
+ radius: "0",
2342
+ d: "M 5,-19 h 19.6 v 48 h -19.6 Z",
2343
+ },
2344
+ {
2345
+ x: "5",
2346
+ y: "341",
2347
+ width: "14.7",
2348
+ height: "48",
2349
+ radius: "0",
2350
+ d: "M 5,341 h 14.7 v 48 h -14.7 Z",
2351
+ },
2352
+ {
2353
+ x: "24.6",
2354
+ y: "-19",
2355
+ width: "117.6",
2356
+ height: "48",
2357
+ radius: "0",
2358
+ d: "M 24.6,-19 h 117.6 v 48 h -117.6 Z",
2359
+ },
2360
+ {
2361
+ x: "19.7",
2362
+ y: "341",
2363
+ width: "223.783",
2364
+ height: "48",
2365
+ radius: "0",
2366
+ d: "M 19.7,341 h 223.783 v 48 h -223.783 Z",
2367
+ },
2368
+ ]);
2369
+ });
2370
+ });
2371
+
2372
+ describe("when stackId is a number", () => {
2373
+ const cells: never[] = [];
2374
+
2375
+ const renderTestCase = createSelectorTestCase((props) => (
2376
+ <BarChart width={100} height={50} data={data}>
2377
+ <YAxis />
2378
+ <Bar dataKey="uv" stackId="8" fill="#ff7300" isAnimationActive={false} />
2379
+ <Bar
2380
+ dataKey="pv"
2381
+ stackId="8"
2382
+ fill="#387908"
2383
+ isAnimationActive={false}
2384
+ minPointSize={0}
2385
+ id="my-bar-id"
2386
+ />
2387
+ {props.children}
2388
+ </BarChart>
2389
+ ));
2390
+
2391
+ it("should select bars", () => {
2392
+ const { spy } = renderTestCase((state) =>
2393
+ selectBarRectangles(state, "my-bar-id", false, cells),
2394
+ );
2395
+ expectLastCalledWith(spy, [
2396
+ {
2397
+ background: {
2398
+ height: 40,
2399
+ width: 6,
2400
+ x: 65.75,
2401
+ y: 5,
2402
+ },
2403
+ height: 9.600000000000001,
2404
+ name: "food",
2405
+ originalDataIndex: 0,
2406
+ payload: {
2407
+ name: "food",
2408
+ pv: 2400,
2409
+ uv: 400,
2410
+ },
2411
+ pv: 2400,
2412
+ stackedBarStart: 45,
2413
+ tooltipPosition: {
2414
+ x: 68.75,
2415
+ y: 38.599999999999994,
2416
+ },
2417
+ uv: 400,
2418
+ value: [400, 2800],
2419
+ width: 6,
2420
+ x: 65.75,
2421
+ y: 33.8,
2422
+ parentViewBox: {
2423
+ height: expect.any(Number),
2424
+ width: expect.any(Number),
2425
+ x: expect.any(Number),
2426
+ y: expect.any(Number),
2427
+ },
2428
+ },
2429
+ {
2430
+ background: {
2431
+ height: 40,
2432
+ width: 6,
2433
+ x: 73.25,
2434
+ y: 5,
2435
+ },
2436
+ height: 18.268,
2437
+ name: "cosmetic",
2438
+ originalDataIndex: 1,
2439
+ payload: {
2440
+ name: "cosmetic",
2441
+ pv: 4567,
2442
+ uv: 300,
2443
+ },
2444
+ pv: 4567,
2445
+ stackedBarStart: 45,
2446
+ tooltipPosition: {
2447
+ x: 76.25,
2448
+ y: 34.666,
2449
+ },
2450
+ uv: 300,
2451
+ value: [300, 4867],
2452
+ width: 6,
2453
+ x: 73.25,
2454
+ y: 25.531999999999996,
2455
+ parentViewBox: {
2456
+ height: expect.any(Number),
2457
+ width: expect.any(Number),
2458
+ x: expect.any(Number),
2459
+ y: expect.any(Number),
2460
+ },
2461
+ },
2462
+ {
2463
+ background: {
2464
+ height: 40,
2465
+ width: 6,
2466
+ x: 80.75,
2467
+ y: 5,
2468
+ },
2469
+ height: 5.591999999999999,
2470
+ name: "storage",
2471
+ originalDataIndex: 2,
2472
+ payload: {
2473
+ name: "storage",
2474
+ pv: 1398,
2475
+ uv: 300,
2476
+ },
2477
+ pv: 1398,
2478
+ stackedBarStart: 45,
2479
+ tooltipPosition: {
2480
+ x: 83.75,
2481
+ y: 41.004,
2482
+ },
2483
+ uv: 300,
2484
+ value: [300, 1698],
2485
+ width: 6,
2486
+ x: 80.75,
2487
+ y: 38.208,
2488
+ parentViewBox: {
2489
+ height: expect.any(Number),
2490
+ width: expect.any(Number),
2491
+ x: expect.any(Number),
2492
+ y: expect.any(Number),
2493
+ },
2494
+ },
2495
+ {
2496
+ background: {
2497
+ height: 40,
2498
+ width: 6,
2499
+ x: 88.25,
2500
+ y: 5,
2501
+ },
2502
+ height: 39.2,
2503
+ name: "digital",
2504
+ originalDataIndex: 3,
2505
+ payload: {
2506
+ name: "digital",
2507
+ pv: 9800,
2508
+ uv: 200,
2509
+ },
2510
+ pv: 9800,
2511
+ stackedBarStart: 45,
2512
+ tooltipPosition: {
2513
+ x: 91.25,
2514
+ y: 24.6,
2515
+ },
2516
+ uv: 200,
2517
+ value: [200, 10000],
2518
+ width: 6,
2519
+ x: 88.25,
2520
+ y: 5,
2521
+ parentViewBox: {
2522
+ height: expect.any(Number),
2523
+ width: expect.any(Number),
2524
+ x: expect.any(Number),
2525
+ y: expect.any(Number),
2526
+ },
2527
+ },
2528
+ ]);
2529
+ });
2530
+
2531
+ it("should select bar size list", () => {
2532
+ const { spy } = renderTestCase((state) => selectBarSizeList(state, "my-bar-id", false));
2533
+ expectLastCalledWith(spy, [
2534
+ {
2535
+ barSize: undefined,
2536
+ dataKeys: ["uv", "pv"],
2537
+ stackId: "8",
2538
+ },
2539
+ ]);
2540
+ });
2541
+
2542
+ test("selectRootMaxBarSize", () => {
2543
+ const { spy } = renderTestCase(selectRootMaxBarSize);
2544
+ expectLastCalledWith(spy, undefined);
2545
+ });
2546
+
2547
+ test("selectBarGap", () => {
2548
+ const { spy } = renderTestCase(selectBarGap);
2549
+ expectLastCalledWith(spy, 4);
2550
+ });
2551
+
2552
+ test("selectBarCategoryGap", () => {
2553
+ const { spy } = renderTestCase(selectBarCategoryGap);
2554
+ expectLastCalledWith(spy, "10%");
2555
+ });
2556
+
2557
+ test("selectBarBandSize", () => {
2558
+ const { spy } = renderTestCase((state) => selectBarBandSize(state, "my-bar-id", false));
2559
+ expectLastCalledWith(spy, 7.5);
2560
+ });
2561
+
2562
+ test("selectAxisBandSize", () => {
2563
+ const { spy } = renderTestCase((state) => selectAxisBandSize(state, "my-bar-id", false));
2564
+ expectLastCalledWith(spy, 7.5);
2565
+ });
2566
+
2567
+ test("selectMaxBarSize", () => {
2568
+ const { spy } = renderTestCase((state) => selectMaxBarSize(state, "my-bar-id"));
2569
+ expectLastCalledWith(spy, undefined);
2570
+ });
2571
+
2572
+ it("should select all bar positions", () => {
2573
+ const { spy } = renderTestCase((state) => selectAllBarPositions(state, "my-bar-id", false));
2574
+ expectLastCalledWith(spy, [
2575
+ {
2576
+ dataKeys: ["uv", "pv"],
2577
+ position: {
2578
+ offset: 0.75,
2579
+ size: 6,
2580
+ },
2581
+ stackId: "8",
2582
+ },
2583
+ ]);
2584
+ });
2585
+
2586
+ it("should select bar position", () => {
2587
+ const { spy } = renderTestCase((state) => selectBarPosition(state, "my-bar-id", false));
2588
+ expectLastCalledWith(spy, {
2589
+ offset: 0.75,
2590
+ size: 6,
2591
+ });
2592
+ });
2593
+
2594
+ it("should render bars", () => {
2595
+ const matchingStackConfig = [
2596
+ { name: "food", firstBarIndex: 0, secondBarIndex: 4 },
2597
+ { name: "cosmetic", firstBarIndex: 1, secondBarIndex: 5 },
2598
+ { name: "storage", firstBarIndex: 2, secondBarIndex: 6 },
2599
+ { name: "digital", firstBarIndex: 3, secondBarIndex: 7 },
2600
+ ];
2601
+
2602
+ const { container } = renderTestCase();
2603
+
2604
+ const rects = container.querySelectorAll(".recharts-rectangle");
2605
+ expect(rects).toHaveLength(8);
2606
+
2607
+ matchingStackConfig.forEach(({ name, firstBarIndex, secondBarIndex }) => {
2608
+ // bar one and bar two should be the same category
2609
+ const barOne = rects[firstBarIndex]!;
2610
+ const barTwo = rects[secondBarIndex]!;
2611
+ expect(barOne.getAttribute("name")).toEqual(name);
2612
+ expect(barTwo.getAttribute("name")).toEqual(name);
2613
+
2614
+ // these bars should have the same x (cannot compare y accurately as Y does not start from 0)
2615
+ expect(barOne.getAttribute("x")).toEqual(barTwo.getAttribute("x"));
2616
+ });
2617
+
2618
+ expectBars(container, [
2619
+ {
2620
+ d: "M 65.75,43.4 h 6 v 1.6 h -6 Z",
2621
+ height: "1.6",
2622
+ radius: "0",
2623
+ width: "6",
2624
+ x: "65.75",
2625
+ y: "43.4",
2626
+ },
2627
+ {
2628
+ d: "M 73.25,43.8 h 6 v 1.2 h -6 Z",
2629
+ height: "1.2",
2630
+ radius: "0",
2631
+ width: "6",
2632
+ x: "73.25",
2633
+ y: "43.8",
2634
+ },
2635
+ {
2636
+ d: "M 80.75,43.8 h 6 v 1.2 h -6 Z",
2637
+ height: "1.2",
2638
+ radius: "0",
2639
+ width: "6",
2640
+ x: "80.75",
2641
+ y: "43.8",
2642
+ },
2643
+ {
2644
+ d: "M 88.25,44.2 h 6 v 0.8 h -6 Z",
2645
+ height: "0.8",
2646
+ radius: "0",
2647
+ width: "6",
2648
+ x: "88.25",
2649
+ y: "44.2",
2650
+ },
2651
+ {
2652
+ d: "M 65.75,33.8 h 6 v 9.6 h -6 Z",
2653
+ height: "9.6",
2654
+ radius: "0",
2655
+ width: "6",
2656
+ x: "65.75",
2657
+ y: "33.8",
2658
+ },
2659
+ {
2660
+ d: "M 73.25,25.532 h 6 v 18.268 h -6 Z",
2661
+ height: "18.268",
2662
+ radius: "0",
2663
+ width: "6",
2664
+ x: "73.25",
2665
+ y: "25.532",
2666
+ },
2667
+ {
2668
+ d: "M 80.75,38.208 h 6 v 5.592 h -6 Z",
2669
+ height: "5.592",
2670
+ radius: "0",
2671
+ width: "6",
2672
+ x: "80.75",
2673
+ y: "38.208",
2674
+ },
2675
+ {
2676
+ d: "M 88.25,5 h 6 v 39.2 h -6 Z",
2677
+ height: "39.2",
2678
+ radius: "0",
2679
+ width: "6",
2680
+ x: "88.25",
2681
+ y: "5",
2682
+ },
2683
+ ]);
2684
+ });
2685
+ });
2686
+
2687
+ describe("rendering bar rectangles", () => {
2688
+ const onePointData = [{ number: 1, name: "food", uv: 400, pv: 2400 }];
2689
+
2690
+ test("renders simple BarChart", () => {
2691
+ const barSpy = vi.fn();
2692
+ const sizeListSpy = vi.fn();
2693
+ const Comp = (): null => {
2694
+ const bars = useAppSelector((state) => selectAllVisibleBars(state, "my-bar-id", false));
2695
+ const sizeList = useAppSelector((state) => selectBarSizeList(state, "my-bar-id", false));
2696
+ createEffect(
2697
+ () => bars(),
2698
+ (v) => barSpy(v),
2699
+ );
2700
+ createEffect(
2701
+ () => sizeList(),
2702
+ (v) => sizeListSpy(v),
2703
+ );
2704
+ return null;
2705
+ };
2706
+ const { container } = render(() => (
2707
+ <BarChart width={100} height={50} data={data}>
2708
+ <Bar dataKey="uv" isAnimationActive={false} id="my-bar-id" />
2709
+ <Comp />
2710
+ </BarChart>
2711
+ ));
2712
+
2713
+ const expectedBar: BarSettings = {
2714
+ id: expect.stringMatching("bar-"),
2715
+ isPanorama: false,
2716
+ maxBarSize: undefined,
2717
+ minPointSize: 0,
2718
+ hasCustomShape: false,
2719
+ barSize: undefined,
2720
+ data: undefined,
2721
+ dataKey: "uv",
2722
+ hide: false,
2723
+ stackId: undefined,
2724
+ type: "bar",
2725
+ xAxisId: 0,
2726
+ yAxisId: 0,
2727
+ zAxisId: 0,
2728
+ };
2729
+ expect(barSpy).toHaveBeenLastCalledWith([expectedBar]);
2730
+
2731
+ expect(sizeListSpy).toHaveBeenLastCalledWith([
2732
+ {
2733
+ barSize: undefined,
2734
+ dataKeys: ["uv"],
2735
+ stackId: undefined,
2736
+ },
2737
+ ]);
2738
+
2739
+ expectBars(container, [
2740
+ {
2741
+ d: "M 7.25,5 h 18 v 40 h -18 Z",
2742
+ height: "40",
2743
+ radius: "0",
2744
+ width: "18",
2745
+ x: "7.25",
2746
+ y: "5",
2747
+ },
2748
+ {
2749
+ d: "M 29.75,15 h 18 v 30 h -18 Z",
2750
+ height: "30",
2751
+ radius: "0",
2752
+ width: "18",
2753
+ x: "29.75",
2754
+ y: "15",
2755
+ },
2756
+ {
2757
+ d: "M 52.25,15 h 18 v 30 h -18 Z",
2758
+ height: "30",
2759
+ radius: "0",
2760
+ width: "18",
2761
+ x: "52.25",
2762
+ y: "15",
2763
+ },
2764
+ {
2765
+ d: "M 74.75,25 h 18 v 20 h -18 Z",
2766
+ height: "20",
2767
+ radius: "0",
2768
+ width: "18",
2769
+ x: "74.75",
2770
+ y: "25",
2771
+ },
2772
+ ]);
2773
+ });
2774
+
2775
+ test("Renders BarChart with two Bars", () => {
2776
+ const { container } = render(() => (
2777
+ <BarChart width={100} height={50} data={data}>
2778
+ <Bar dataKey="uv" isAnimationActive={false} />
2779
+ <Bar dataKey="pv" isAnimationActive={false} />
2780
+ </BarChart>
2781
+ ));
2782
+
2783
+ expectBars(container, [
2784
+ {
2785
+ d: "M 7.25,43.4 h 7 v 1.6 h -7 Z",
2786
+ height: "1.6",
2787
+ radius: "0",
2788
+ width: "7",
2789
+ x: "7.25",
2790
+ y: "43.4",
2791
+ },
2792
+ {
2793
+ d: "M 29.75,43.8 h 7 v 1.2 h -7 Z",
2794
+ height: "1.2",
2795
+ radius: "0",
2796
+ width: "7",
2797
+ x: "29.75",
2798
+ y: "43.8",
2799
+ },
2800
+ {
2801
+ d: "M 52.25,43.8 h 7 v 1.2 h -7 Z",
2802
+ height: "1.2",
2803
+ radius: "0",
2804
+ width: "7",
2805
+ x: "52.25",
2806
+ y: "43.8",
2807
+ },
2808
+ {
2809
+ d: "M 74.75,44.2 h 7 v 0.8 h -7 Z",
2810
+ height: "0.8",
2811
+ radius: "0",
2812
+ width: "7",
2813
+ x: "74.75",
2814
+ y: "44.2",
2815
+ },
2816
+ {
2817
+ d: "M 18.25,35.4 h 7 v 9.6 h -7 Z",
2818
+ height: "9.6",
2819
+ radius: "0",
2820
+ width: "7",
2821
+ x: "18.25",
2822
+ y: "35.4",
2823
+ },
2824
+ {
2825
+ d: "M 40.75,26.732 h 7 v 18.268 h -7 Z",
2826
+ height: "18.268",
2827
+ radius: "0",
2828
+ width: "7",
2829
+ x: "40.75",
2830
+ y: "26.732",
2831
+ },
2832
+ {
2833
+ d: "M 63.25,39.408 h 7 v 5.592 h -7 Z",
2834
+ height: "5.592",
2835
+ radius: "0",
2836
+ width: "7",
2837
+ x: "63.25",
2838
+ y: "39.408",
2839
+ },
2840
+ {
2841
+ d: "M 85.75,5.8 h 7 v 39.2 h -7 Z",
2842
+ height: "39.2",
2843
+ radius: "0",
2844
+ width: "7",
2845
+ x: "85.75",
2846
+ y: "5.8",
2847
+ },
2848
+ ]);
2849
+ });
2850
+
2851
+ test("Don't renders any bars when no Bar item is added", () => {
2852
+ const { container } = render(() => <BarChart width={100} height={50} data={data} />);
2853
+
2854
+ expect(container.querySelectorAll(".recharts-rectangle")).toHaveLength(0);
2855
+ });
2856
+
2857
+ test("Renders 8 bars in a vertical BarChart", () => {
2858
+ const { container } = render(() => (
2859
+ <BarChart width={100} height={50} data={data} layout="vertical">
2860
+ <XAxis type="number" />
2861
+ <YAxis type="category" dataKey="name" />
2862
+ <Bar dataKey="uv" fill="#ff7300" isAnimationActive={false} />
2863
+ <Bar dataKey="pv" fill="#387908" isAnimationActive={false} />
2864
+ </BarChart>
2865
+ ));
2866
+
2867
+ expectBars(container, [
2868
+ {
2869
+ d: "M 65,5.25 h 1.2 v 1 h -1.2 Z",
2870
+ height: "1",
2871
+ radius: "0",
2872
+ width: "1.2",
2873
+ x: "65",
2874
+ y: "5.25",
2875
+ },
2876
+ {
2877
+ d: "M 65,7.75 h 0.9 v 1 h -0.9 Z",
2878
+ height: "1",
2879
+ radius: "0",
2880
+ width: "0.9",
2881
+ x: "65",
2882
+ y: "7.75",
2883
+ },
2884
+ {
2885
+ d: "M 65,10.25 h 0.9 v 1 h -0.9 Z",
2886
+ height: "1",
2887
+ radius: "0",
2888
+ width: "0.9",
2889
+ x: "65",
2890
+ y: "10.25",
2891
+ },
2892
+ {
2893
+ d: "M 65,12.75 h 0.6 v 1 h -0.6 Z",
2894
+ height: "1",
2895
+ radius: "0",
2896
+ width: "0.6",
2897
+ x: "65",
2898
+ y: "12.75",
2899
+ },
2900
+ {
2901
+ d: "M 65,6.25 h 7.2 v 1 h -7.2 Z",
2902
+ height: "1",
2903
+ radius: "0",
2904
+ width: "7.2",
2905
+ x: "65",
2906
+ y: "6.25",
2907
+ },
2908
+ {
2909
+ d: "M 65,8.75 h 13.701 v 1 h -13.701 Z",
2910
+ height: "1",
2911
+ radius: "0",
2912
+ width: "13.701",
2913
+ x: "65",
2914
+ y: "8.75",
2915
+ },
2916
+ {
2917
+ d: "M 65,11.25 h 4.194 v 1 h -4.194 Z",
2918
+ height: "1",
2919
+ radius: "0",
2920
+ width: "4.194",
2921
+ x: "65",
2922
+ y: "11.25",
2923
+ },
2924
+ {
2925
+ d: "M 65,13.75 h 29.4 v 1 h -29.4 Z",
2926
+ height: "1",
2927
+ radius: "0",
2928
+ width: "29.4",
2929
+ x: "65",
2930
+ y: "13.75",
2931
+ },
2932
+ ]);
2933
+ });
2934
+
2935
+ test("Renders 8 bars in a stacked BarChart, Bars of the same category have the same name and same x pos", () => {
2936
+ const matchingStackConfig = [
2937
+ { name: "food", firstBarIndex: 0, secondBarIndex: 4 },
2938
+ { name: "cosmetic", firstBarIndex: 1, secondBarIndex: 5 },
2939
+ { name: "storage", firstBarIndex: 2, secondBarIndex: 6 },
2940
+ { name: "digital", firstBarIndex: 3, secondBarIndex: 7 },
2941
+ ];
2942
+
2943
+ const { container } = render(() => (
2944
+ <BarChart width={100} height={50} data={data}>
2945
+ <YAxis />
2946
+ <Bar dataKey="uv" stackId="test" fill="#ff7300" isAnimationActive={false} />
2947
+ <Bar dataKey="pv" stackId="test" fill="#387908" isAnimationActive={false} />
2948
+ </BarChart>
2949
+ ));
2950
+
2951
+ const rects = container.querySelectorAll(".recharts-rectangle");
2952
+ expect(rects).toHaveLength(8);
2953
+
2954
+ matchingStackConfig.forEach(({ name, firstBarIndex, secondBarIndex }) => {
2955
+ // bar one and bar two should be the same category
2956
+ const barOne = rects[firstBarIndex]!;
2957
+ const barTwo = rects[secondBarIndex]!;
2958
+ expect(barOne.getAttribute("name")).toEqual(name);
2959
+ expect(barTwo.getAttribute("name")).toEqual(name);
2960
+
2961
+ // these bars should have the same x (cannot compare y accurately as Y does not start from 0)
2962
+ expect(barOne.getAttribute("x")).toEqual(barTwo.getAttribute("x"));
2963
+ });
2964
+
2965
+ expectBars(container, [
2966
+ {
2967
+ d: "M 65.75,43.4 h 6 v 1.6 h -6 Z",
2968
+ height: "1.6",
2969
+ radius: "0",
2970
+ width: "6",
2971
+ x: "65.75",
2972
+ y: "43.4",
2973
+ },
2974
+ {
2975
+ d: "M 73.25,43.8 h 6 v 1.2 h -6 Z",
2976
+ height: "1.2",
2977
+ radius: "0",
2978
+ width: "6",
2979
+ x: "73.25",
2980
+ y: "43.8",
2981
+ },
2982
+ {
2983
+ d: "M 80.75,43.8 h 6 v 1.2 h -6 Z",
2984
+ height: "1.2",
2985
+ radius: "0",
2986
+ width: "6",
2987
+ x: "80.75",
2988
+ y: "43.8",
2989
+ },
2990
+ {
2991
+ d: "M 88.25,44.2 h 6 v 0.8 h -6 Z",
2992
+ height: "0.8",
2993
+ radius: "0",
2994
+ width: "6",
2995
+ x: "88.25",
2996
+ y: "44.2",
2997
+ },
2998
+ {
2999
+ d: "M 65.75,33.8 h 6 v 9.6 h -6 Z",
3000
+ height: "9.6",
3001
+ radius: "0",
3002
+ width: "6",
3003
+ x: "65.75",
3004
+ y: "33.8",
3005
+ },
3006
+ {
3007
+ d: "M 73.25,25.532 h 6 v 18.268 h -6 Z",
3008
+ height: "18.268",
3009
+ radius: "0",
3010
+ width: "6",
3011
+ x: "73.25",
3012
+ y: "25.532",
3013
+ },
3014
+ {
3015
+ d: "M 80.75,38.208 h 6 v 5.592 h -6 Z",
3016
+ height: "5.592",
3017
+ radius: "0",
3018
+ width: "6",
3019
+ x: "80.75",
3020
+ y: "38.208",
3021
+ },
3022
+ {
3023
+ d: "M 88.25,5 h 6 v 39.2 h -6 Z",
3024
+ height: "39.2",
3025
+ radius: "0",
3026
+ width: "6",
3027
+ x: "88.25",
3028
+ y: "5",
3029
+ },
3030
+ ]);
3031
+ });
3032
+
3033
+ test("renders a horizontal stacked bar chart when x-axis is of type number", () => {
3034
+ const dataWithNumberAsKey = [
3035
+ { xKey: 4000, uv: 400, pv: 2400 },
3036
+ { xKey: 6000, uv: 300, pv: 4567 },
3037
+ { xKey: 8000, uv: 300, pv: 1398 },
3038
+ { xKey: 10000, uv: 200, pv: 9800 },
3039
+ ];
3040
+
3041
+ const { container } = render(() => (
3042
+ <BarChart width={500} height={400} data={dataWithNumberAsKey}>
3043
+ <XAxis type="number" dataKey="xKey" domain={["dataMin", "dataMax"]} />
3044
+ <Bar dataKey="uv" stackId="test" fill="#ff7300" isAnimationActive={false} />
3045
+ <Bar dataKey="pv" stackId="test" fill="#387908" isAnimationActive={false} />
3046
+ </BarChart>
3047
+ ));
3048
+
3049
+ expectBars(container, [
3050
+ {
3051
+ x: "-60.3333",
3052
+ y: "350.6",
3053
+ width: "131",
3054
+ height: "14.4",
3055
+ radius: "0",
3056
+ d: "M -60.3333,350.6 h 131 v 14.4 h -131 Z",
3057
+ },
3058
+ {
3059
+ x: "103",
3060
+ y: "354.2",
3061
+ width: "131",
3062
+ height: "10.8",
3063
+ radius: "0",
3064
+ d: "M 103,354.2 h 131 v 10.8 h -131 Z",
3065
+ },
3066
+ {
3067
+ x: "266.3333",
3068
+ y: "354.2",
3069
+ width: "131",
3070
+ height: "10.8",
3071
+ radius: "0",
3072
+ d: "M 266.3333,354.2 h 131 v 10.8 h -131 Z",
3073
+ },
3074
+ {
3075
+ x: "429.6667",
3076
+ y: "357.8",
3077
+ width: "131",
3078
+ height: "7.2",
3079
+ radius: "0",
3080
+ d: "M 429.6667,357.8 h 131 v 7.2 h -131 Z",
3081
+ },
3082
+ {
3083
+ x: "-60.3333",
3084
+ y: "264.2",
3085
+ width: "131",
3086
+ height: "86.4",
3087
+ radius: "0",
3088
+ d: "M -60.3333,264.2 h 131 v 86.4 h -131 Z",
3089
+ },
3090
+ {
3091
+ x: "103",
3092
+ y: "189.788",
3093
+ width: "131",
3094
+ height: "164.412",
3095
+ radius: "0",
3096
+ d: "M 103,189.788 h 131 v 164.412 h -131 Z",
3097
+ },
3098
+ {
3099
+ x: "266.3333",
3100
+ y: "303.872",
3101
+ width: "131",
3102
+ height: "50.328",
3103
+ radius: "0",
3104
+ d: "M 266.3333,303.872 h 131 v 50.328 h -131 Z",
3105
+ },
3106
+ {
3107
+ x: "429.6667",
3108
+ y: "5",
3109
+ width: "131",
3110
+ height: "352.8",
3111
+ radius: "0",
3112
+ d: "M 429.6667,5 h 131 v 352.8 h -131 Z",
3113
+ },
3114
+ ]);
3115
+ });
3116
+
3117
+ test("Stacked bars are actually stacked", () => {
3118
+ const seriesOne = vi.fn();
3119
+ const seriesTwo = vi.fn();
3120
+ const Spy = (): null => {
3121
+ const a = useAppSelector((state) => selectBarRectangles(state, "bar-uv", false, []));
3122
+ const b = useAppSelector((state) => selectBarRectangles(state, "bar-pv", false, []));
3123
+ createEffect(
3124
+ () => a()?.[0],
3125
+ (v) => seriesOne(v),
3126
+ );
3127
+ createEffect(
3128
+ () => b()?.[0],
3129
+ (v) => seriesTwo(v),
3130
+ );
3131
+ return null;
3132
+ };
3133
+
3134
+ const { container } = render(() => (
3135
+ <BarChart width={100} height={50} data={data}>
3136
+ <YAxis />
3137
+ <Bar dataKey="uv" stackId="test" fill="#ff7300" isAnimationActive={false} id="bar-uv" />
3138
+ <Bar dataKey="pv" stackId="test" fill="#387908" isAnimationActive={false} id="bar-pv">
3139
+ <Spy />
3140
+ </Bar>
3141
+ </BarChart>
3142
+ ));
3143
+ flush();
3144
+
3145
+ expect(seriesOne.mock.lastCall?.[0]?.value).toEqual([0, 400]);
3146
+ expect(seriesTwo.mock.lastCall?.[0]?.value).toEqual([400, 2800]);
3147
+
3148
+ expectBars(container, [
3149
+ {
3150
+ d: "M 65.75,43.4 h 6 v 1.6 h -6 Z",
3151
+ height: "1.6",
3152
+ radius: "0",
3153
+ width: "6",
3154
+ x: "65.75",
3155
+ y: "43.4",
3156
+ },
3157
+ {
3158
+ d: "M 73.25,43.8 h 6 v 1.2 h -6 Z",
3159
+ height: "1.2",
3160
+ radius: "0",
3161
+ width: "6",
3162
+ x: "73.25",
3163
+ y: "43.8",
3164
+ },
3165
+ {
3166
+ d: "M 80.75,43.8 h 6 v 1.2 h -6 Z",
3167
+ height: "1.2",
3168
+ radius: "0",
3169
+ width: "6",
3170
+ x: "80.75",
3171
+ y: "43.8",
3172
+ },
3173
+ {
3174
+ d: "M 88.25,44.2 h 6 v 0.8 h -6 Z",
3175
+ height: "0.8",
3176
+ radius: "0",
3177
+ width: "6",
3178
+ x: "88.25",
3179
+ y: "44.2",
3180
+ },
3181
+ {
3182
+ d: "M 65.75,33.8 h 6 v 9.6 h -6 Z",
3183
+ height: "9.6",
3184
+ radius: "0",
3185
+ width: "6",
3186
+ x: "65.75",
3187
+ y: "33.8",
3188
+ },
3189
+ {
3190
+ d: "M 73.25,25.532 h 6 v 18.268 h -6 Z",
3191
+ height: "18.268",
3192
+ radius: "0",
3193
+ width: "6",
3194
+ x: "73.25",
3195
+ y: "25.532",
3196
+ },
3197
+ {
3198
+ d: "M 80.75,38.208 h 6 v 5.592 h -6 Z",
3199
+ height: "5.592",
3200
+ radius: "0",
3201
+ width: "6",
3202
+ x: "80.75",
3203
+ y: "38.208",
3204
+ },
3205
+ {
3206
+ d: "M 88.25,5 h 6 v 39.2 h -6 Z",
3207
+ height: "39.2",
3208
+ radius: "0",
3209
+ width: "6",
3210
+ x: "88.25",
3211
+ y: "5",
3212
+ },
3213
+ ]);
3214
+ });
3215
+
3216
+ test("Renders 4 bars in a stacked BarChart which only have one Bar", () => {
3217
+ const { container } = render(() => (
3218
+ <BarChart width={100} height={50} data={data}>
3219
+ <YAxis />
3220
+ <Bar dataKey="uv" stackId="test" fill="#ff7300" isAnimationActive={false} />
3221
+ </BarChart>
3222
+ ));
3223
+ flush();
3224
+
3225
+ expect(container.querySelectorAll(".recharts-rectangle")).toHaveLength(4);
3226
+ });
3227
+
3228
+ // https://github.com/recharts/recharts/issues/6235
3229
+ test("Stacked bars with all 0 values: Bar component and YAxis ticks still render", () => {
3230
+ const allZeroData = [
3231
+ { name: "Page A", uv: 0, pv: 0 },
3232
+ { name: "Page B", uv: 0, pv: 0 },
3233
+ { name: "Page C", uv: 0, pv: 0 },
3234
+ ];
3235
+ const { container } = render(() => (
3236
+ <BarChart width={400} height={300} data={allZeroData}>
3237
+ <YAxis />
3238
+ <Bar dataKey="uv" stackId="test" fill="#ff7300" isAnimationActive={false} />
3239
+ <Bar dataKey="pv" stackId="test" fill="#387908" isAnimationActive={false} />
3240
+ </BarChart>
3241
+ ));
3242
+ flush();
3243
+
3244
+ // Zero-height bars without custom shapes are filtered, but the Bar component itself renders.
3245
+ expect(container.querySelectorAll(".recharts-bar-rectangle")).toHaveLength(0);
3246
+ expect(container.querySelectorAll(".recharts-bar")).toHaveLength(2);
3247
+ expect(
3248
+ container.querySelectorAll(".recharts-yAxis .recharts-cartesian-axis-tick"),
3249
+ ).not.toHaveLength(0);
3250
+ });
3251
+
3252
+ // https://github.com/recharts/recharts/issues/6235
3253
+ test("Renders stacked bars with custom shape when all values are 0", () => {
3254
+ const allZeroData = [
3255
+ { name: "Page A", uv: 0, pv: 0 },
3256
+ { name: "Page B", uv: 0, pv: 0 },
3257
+ ];
3258
+ const customShape = vi.fn(() => <rect data-testid="custom-shape" />);
3259
+ const { container } = render(() => (
3260
+ <BarChart width={400} height={300} data={allZeroData}>
3261
+ <YAxis />
3262
+ <Bar dataKey="uv" stackId="test" shape={customShape} isAnimationActive={false} />
3263
+ </BarChart>
3264
+ ));
3265
+ flush();
3266
+
3267
+ expect(customShape).toHaveBeenCalled();
3268
+ expect(container.querySelectorAll('[data-testid="custom-shape"]')).toHaveLength(2);
3269
+ });
3270
+
3271
+ // https://github.com/recharts/recharts/issues/6235
3272
+ test("Vertical stacked bars with all 0 values still render custom shapes", () => {
3273
+ const allZeroData = [
3274
+ { name: "Page A", uv: 0, pv: 0 },
3275
+ { name: "Page B", uv: 0, pv: 0 },
3276
+ ];
3277
+ const customShape = vi.fn(() => <rect data-testid="custom-shape" />);
3278
+ const { container } = render(() => (
3279
+ <BarChart width={400} height={300} data={allZeroData} layout="vertical">
3280
+ <XAxis type="number" />
3281
+ <YAxis dataKey="name" type="category" />
3282
+ <Bar dataKey="uv" stackId="test" shape={customShape} isAnimationActive={false} />
3283
+ </BarChart>
3284
+ ));
3285
+ flush();
3286
+
3287
+ expect(customShape).toHaveBeenCalled();
3288
+ expect(container.querySelectorAll('[data-testid="custom-shape"]')).toHaveLength(2);
3289
+ });
3290
+
3291
+ test("renders nothing if barSize is not specified in a numerical XAxis", () => {
3292
+ const { container } = render(() => (
3293
+ <BarChart width={100} height={50} data={onePointData}>
3294
+ <XAxis dataKey="number" type="number" />
3295
+ <Bar dataKey="uv" name="uv" isAnimationActive={false} />
3296
+ </BarChart>
3297
+ ));
3298
+ flush();
3299
+ expectBars(container, []);
3300
+ });
3301
+
3302
+ test("renders bars of default size if barSize is not set in categorical XAxis", () => {
3303
+ const { container } = render(() => (
3304
+ <BarChart width={100} height={50} data={onePointData}>
3305
+ <XAxis dataKey="number" />
3306
+ <Bar dataKey="uv" name="uv" isAnimationActive={false} />
3307
+ </BarChart>
3308
+ ));
3309
+ flush();
3310
+ expectBars(container, [
3311
+ { d: "M 14,5 h 72 v 10 h -72 Z", height: "10", radius: "0", width: "72", x: "14", y: "5" },
3312
+ ]);
3313
+ });
3314
+
3315
+ test("renders a bar of custom width if size is specified", () => {
3316
+ const { container } = render(() => (
3317
+ <BarChart width={100} height={50} data={onePointData} barSize={20}>
3318
+ <XAxis dataKey="number" type="number" />
3319
+ <Bar dataKey="uv" name="uv" isAnimationActive={false} />
3320
+ </BarChart>
3321
+ ));
3322
+ flush();
3323
+ expectBars(container, [
3324
+ { d: "M 85,5 h 20 v 10 h -20 Z", height: "10", radius: "0", width: "20", x: "85", y: "5" },
3325
+ ]);
3326
+ });
3327
+
3328
+ test("renders bar when barSize is set in %", () => {
3329
+ const { container } = render(() => (
3330
+ <BarChart width={100} height={50} data={onePointData} barSize="40%">
3331
+ <XAxis dataKey="number" />
3332
+ <Bar dataKey="uv" name="uv" isAnimationActive={false} />
3333
+ </BarChart>
3334
+ ));
3335
+ flush();
3336
+ expectBars(container, [
3337
+ { d: "M 32,5 h 36 v 10 h -36 Z", height: "10", radius: "0", width: "36", x: "32", y: "5" },
3338
+ ]);
3339
+ });
3340
+
3341
+ test("prefers child item barSize if both child and global barSize are set", () => {
3342
+ const { container } = render(() => (
3343
+ <BarChart width={100} height={50} data={onePointData} barSize={20}>
3344
+ <XAxis dataKey="number" type="number" />
3345
+ <Bar dataKey="uv" name="uv" isAnimationActive={false} barSize={40} />
3346
+ </BarChart>
3347
+ ));
3348
+ flush();
3349
+ expectBars(container, [
3350
+ { d: "M 75,5 h 40 v 10 h -40 Z", height: "10", radius: "0", width: "40", x: "75", y: "5" },
3351
+ ]);
3352
+ });
3353
+
3354
+ test("renders a smaller bar if maxBarSize is set, even in a numerical XAxis", () => {
3355
+ const barSizeListSpy = vi.fn();
3356
+ const barPositionsSpy = vi.fn();
3357
+ const totalAxisSizeSpy = vi.fn();
3358
+ const Comp = (): null => {
3359
+ const sizeList = useAppSelector((state) => selectBarSizeList(state, "my-bar-id", false));
3360
+ const positions = useAppSelector((state) => selectAllBarPositions(state, "my-bar-id", false));
3361
+ const axisSize = useAppSelector((state) => selectBarCartesianAxisSize(state, "my-bar-id"));
3362
+ createEffect(
3363
+ () => sizeList(),
3364
+ (v) => barSizeListSpy(v),
3365
+ );
3366
+ createEffect(
3367
+ () => positions(),
3368
+ (v) => barPositionsSpy(v),
3369
+ );
3370
+ createEffect(
3371
+ () => axisSize(),
3372
+ (v) => totalAxisSizeSpy(v),
3373
+ );
3374
+ return null;
3375
+ };
3376
+
3377
+ const { container } = render(() => (
3378
+ <BarChart width={100} height={50} data={onePointData}>
3379
+ <XAxis dataKey="number" type="number" />
3380
+ <Bar dataKey="uv" name="uv" isAnimationActive={false} maxBarSize={30} id="my-bar-id" />
3381
+ <Comp />
3382
+ </BarChart>
3383
+ ));
3384
+ flush();
3385
+
3386
+ expect(barSizeListSpy).toHaveBeenLastCalledWith([
3387
+ { barSize: undefined, dataKeys: ["uv"], stackId: undefined },
3388
+ ]);
3389
+ expect(totalAxisSizeSpy).toHaveBeenLastCalledWith(90);
3390
+ expect(barPositionsSpy).toHaveBeenLastCalledWith([
3391
+ { position: { offset: -12, size: 24 }, dataKeys: ["uv"], stackId: undefined },
3392
+ ]);
3393
+
3394
+ expectBars(container, [
3395
+ { d: "M 83,5 h 24 v 10 h -24 Z", height: "10", radius: "0", width: "24", x: "83", y: "5" },
3396
+ ]);
3397
+ });
3398
+
3399
+ test("renders a smaller bar if maxBarSize is set with categorical XAxis", () => {
3400
+ const { container } = render(() => (
3401
+ <BarChart width={100} height={50} data={onePointData}>
3402
+ <XAxis dataKey="number" />
3403
+ <Bar dataKey="uv" name="uv" isAnimationActive={false} maxBarSize={40} />
3404
+ </BarChart>
3405
+ ));
3406
+ flush();
3407
+ expectBars(container, [
3408
+ { d: "M 30,5 h 40 v 10 h -40 Z", height: "10", radius: "0", width: "40", x: "30", y: "5" },
3409
+ ]);
3410
+ });
3411
+
3412
+ test("if graphical item barSize is larger than maxBarSize then the barSize should win", () => {
3413
+ const { container } = render(() => (
3414
+ <BarChart width={100} height={50} data={onePointData}>
3415
+ <XAxis dataKey="number" />
3416
+ <Bar dataKey="uv" name="uv" isAnimationActive={false} barSize={60} maxBarSize={40} />
3417
+ </BarChart>
3418
+ ));
3419
+ flush();
3420
+ expectBars(container, [
3421
+ { d: "M 20,5 h 60 v 10 h -60 Z", height: "10", radius: "0", width: "60", x: "20", y: "5" },
3422
+ ]);
3423
+ });
3424
+
3425
+ test("if chart root barSize is larger than maxBarSize then the barSize should win", () => {
3426
+ const { container } = render(() => (
3427
+ <BarChart width={100} height={50} data={onePointData} barSize={60}>
3428
+ <XAxis dataKey="number" />
3429
+ <Bar dataKey="uv" name="uv" isAnimationActive={false} maxBarSize={40} />
3430
+ </BarChart>
3431
+ ));
3432
+ flush();
3433
+ expectBars(container, [
3434
+ { d: "M 20,5 h 60 v 10 h -60 Z", height: "10", radius: "0", width: "60", x: "20", y: "5" },
3435
+ ]);
3436
+ });
3437
+
3438
+ // PERMANENT-N/A: "renders bars in Brush panorama" — the outer ComposedChart's
3439
+ // own bars and the in-brush panorama-mirror bars share a y-domain/plot-area
3440
+ // differently in this port than in recharts (the reference renders 14 bars with
3441
+ // the outer set scaled to a tiny top band; the port renders the panorama mirror
3442
+ // and re-scales the outer set, yielding a different bar count + geometry). This
3443
+ // is a Brush-panorama × ComposedChart shared-domain LAYOUT divergence (tracked in
3444
+ // the Brush/panorama infra), not a Bar feature gap — the Bar-level bar positions
3445
+ // selector (offset 11.2857 / size 90) is already correct.
3446
+
3447
+ test("should render whiskers in boxplot simulation", () => {
3448
+ const barPositionsSpy = vi.fn();
3449
+ const barRectanglesSpy = vi.fn();
3450
+ const Comp = (): null => {
3451
+ const positions = useAppSelector((state) => selectAllBarPositions(state, "my-bar-id", false));
3452
+ const rects = useAppSelector((state) =>
3453
+ selectBarRectangles(state, "my-bar-id", false, undefined),
3454
+ );
3455
+ createEffect(
3456
+ () => positions(),
3457
+ (v) => barPositionsSpy(v),
3458
+ );
3459
+ createEffect(
3460
+ () => rects(),
3461
+ (v) => barRectanglesSpy(v),
3462
+ );
3463
+ return null;
3464
+ };
3465
+
3466
+ const { container } = render(() => (
3467
+ <ComposedChart width={400} height={200} data={boxPlotData}>
3468
+ <Bar stackId="a" dataKey="min" isAnimationActive={false} />
3469
+ <Bar stackId="a" dataKey="bar-min" isAnimationActive={false} />
3470
+ <Bar stackId="a" dataKey="bottomWhisker" isAnimationActive={false} />
3471
+ <Bar stackId="a" dataKey="bottomBox" isAnimationActive={false} />
3472
+ <Bar stackId="a" dataKey="bar-avg" isAnimationActive={false} />
3473
+ <Bar stackId="a" dataKey="topBox" isAnimationActive={false} />
3474
+ <Bar stackId="a" dataKey="topWhisker" isAnimationActive={false} id="my-bar-id" />
3475
+ <Bar stackId="a" dataKey="bar-max" isAnimationActive={false} />
3476
+ <XAxis />
3477
+ <YAxis />
3478
+ <Comp />
3479
+ </ComposedChart>
3480
+ ));
3481
+ flush();
3482
+
3483
+ expect(barPositionsSpy).toHaveBeenLastCalledWith([
3484
+ {
3485
+ dataKeys: [
3486
+ "min",
3487
+ "bar-min",
3488
+ "bottomWhisker",
3489
+ "bottomBox",
3490
+ "bar-avg",
3491
+ "topBox",
3492
+ "topWhisker",
3493
+ "bar-max",
3494
+ ],
3495
+ position: { offset: 11, size: 88 },
3496
+ stackId: "a",
3497
+ },
3498
+ ]);
3499
+ expect(barRectanglesSpy).toHaveBeenLastCalledWith([
3500
+ expect.objectContaining({
3501
+ originalDataIndex: 0,
3502
+ value: [450, 650],
3503
+ width: 88,
3504
+ x: 76,
3505
+ y: 35,
3506
+ height: 40,
3507
+ stackedBarStart: 165,
3508
+ tooltipPosition: { x: 120, y: 55 },
3509
+ background: { height: 160, width: 88, x: 76, y: 5 },
3510
+ }),
3511
+ expect.objectContaining({
3512
+ originalDataIndex: 1,
3513
+ value: [700, 800],
3514
+ width: 88,
3515
+ x: 186,
3516
+ y: 5,
3517
+ height: 20,
3518
+ tooltipPosition: { x: 230, y: 15 },
3519
+ }),
3520
+ expect.objectContaining({
3521
+ originalDataIndex: 2,
3522
+ value: [600, 800],
3523
+ width: 88,
3524
+ x: 296,
3525
+ y: 5,
3526
+ height: 40,
3527
+ tooltipPosition: { x: 340, y: 25 },
3528
+ }),
3529
+ ]);
3530
+
3531
+ expectBars(container, [
3532
+ {
3533
+ d: "M 76,145 h 88 v 20 h -88 Z",
3534
+ height: "20",
3535
+ radius: "0",
3536
+ width: "88",
3537
+ x: "76",
3538
+ y: "145",
3539
+ },
3540
+ {
3541
+ d: "M 186,125 h 88 v 40 h -88 Z",
3542
+ height: "40",
3543
+ radius: "0",
3544
+ width: "88",
3545
+ x: "186",
3546
+ y: "125",
3547
+ },
3548
+ {
3549
+ d: "M 76,125 h 88 v 20 h -88 Z",
3550
+ height: "20",
3551
+ radius: "0",
3552
+ width: "88",
3553
+ x: "76",
3554
+ y: "125",
3555
+ },
3556
+ {
3557
+ d: "M 186,85 h 88 v 40 h -88 Z",
3558
+ height: "40",
3559
+ radius: "0",
3560
+ width: "88",
3561
+ x: "186",
3562
+ y: "85",
3563
+ },
3564
+ {
3565
+ d: "M 296,125 h 88 v 40 h -88 Z",
3566
+ height: "40",
3567
+ radius: "0",
3568
+ width: "88",
3569
+ x: "296",
3570
+ y: "125",
3571
+ },
3572
+ {
3573
+ d: "M 76,115 h 88 v 10 h -88 Z",
3574
+ height: "10",
3575
+ radius: "0",
3576
+ width: "88",
3577
+ x: "76",
3578
+ y: "115",
3579
+ },
3580
+ {
3581
+ d: "M 186,45 h 88 v 40 h -88 Z",
3582
+ height: "40",
3583
+ radius: "0",
3584
+ width: "88",
3585
+ x: "186",
3586
+ y: "45",
3587
+ },
3588
+ {
3589
+ d: "M 296,85 h 88 v 40 h -88 Z",
3590
+ height: "40",
3591
+ radius: "0",
3592
+ width: "88",
3593
+ x: "296",
3594
+ y: "85",
3595
+ },
3596
+ { d: "M 76,75 h 88 v 40 h -88 Z", height: "40", radius: "0", width: "88", x: "76", y: "75" },
3597
+ {
3598
+ d: "M 186,25 h 88 v 20 h -88 Z",
3599
+ height: "20",
3600
+ radius: "0",
3601
+ width: "88",
3602
+ x: "186",
3603
+ y: "25",
3604
+ },
3605
+ {
3606
+ d: "M 296,45 h 88 v 40 h -88 Z",
3607
+ height: "40",
3608
+ radius: "0",
3609
+ width: "88",
3610
+ x: "296",
3611
+ y: "45",
3612
+ },
3613
+ { d: "M 76,35 h 88 v 40 h -88 Z", height: "40", radius: "0", width: "88", x: "76", y: "35" },
3614
+ { d: "M 186,5 h 88 v 20 h -88 Z", height: "20", radius: "0", width: "88", x: "186", y: "5" },
3615
+ { d: "M 296,5 h 88 v 40 h -88 Z", height: "40", radius: "0", width: "88", x: "296", y: "5" },
3616
+ ]);
3617
+ });
3618
+ });
3619
+
3620
+ // Ported from recharts 3.8.1 test/chart/BarChart.spec.tsx `describe('chart
3621
+ // synchronization')`. Solid adaptations: tooltips portal into each chart's own
3622
+ // `.recharts-wrapper`, so we scope queries per wrapper (`getTooltip(wrapper)`)
3623
+ // rather than indexing a flat `querySelectorAll`; hover/leave settle via the
3624
+ // helpers' `flush()` (no fake timers / `act`). Mouse triggers go through the
3625
+ // chart surface (`.recharts-wrapper`), the bar-chart axis-tooltip selector.
3626
+ describe("BarChart chart synchronization", () => {
3627
+ beforeEach(() => {
3628
+ mockGetBoundingClientRect({ width: 100, height: 100 });
3629
+ });
3630
+
3631
+ it("should render two independent charts by default", () => {
3632
+ const { container } = render(() => (
3633
+ <>
3634
+ <div id="barOne">
3635
+ <BarChart width={100} height={50} data={data}>
3636
+ <Bar dataKey="uv" />
3637
+ <Tooltip />
3638
+ </BarChart>
3639
+ </div>
3640
+ <div id="barTwo">
3641
+ <BarChart width={100} height={50} data={data}>
3642
+ <Bar dataKey="pv" />
3643
+ <Tooltip />
3644
+ </BarChart>
3645
+ </div>
3646
+ </>
3647
+ ));
3648
+
3649
+ const wrapperOne = container.querySelector("#barOne");
3650
+ assertNotNull(wrapperOne);
3651
+ const wrapperTwo = container.querySelector("#barTwo");
3652
+ assertNotNull(wrapperTwo);
3653
+
3654
+ expectTooltipNotVisible(wrapperOne);
3655
+ expectTooltipNotVisible(wrapperTwo);
3656
+
3657
+ // Hovering chart one shows ONLY chart one's tooltip (no syncId).
3658
+ showTooltipOnCoordinate(wrapperOne, barChartMouseHoverTooltipSelector, {
3659
+ clientX: 20,
3660
+ clientY: 20,
3661
+ });
3662
+ expect(getTooltip(wrapperOne)).toBeVisible();
3663
+ expectTooltipNotVisible(wrapperTwo);
3664
+
3665
+ showTooltipOnCoordinate(wrapperTwo, barChartMouseHoverTooltipSelector, {
3666
+ clientX: 20,
3667
+ clientY: 20,
3668
+ });
3669
+ expectTooltipPayload(wrapperOne, "0", ["uv : 400"]);
3670
+ expectTooltipPayload(wrapperTwo, "0", ["pv : 2400"]);
3671
+
3672
+ hideTooltip(wrapperOne, barChartMouseHoverTooltipSelector);
3673
+ expectTooltipNotVisible(wrapperOne);
3674
+ expect(getTooltip(wrapperTwo)).toBeVisible();
3675
+
3676
+ hideTooltip(wrapperTwo, barChartMouseHoverTooltipSelector);
3677
+ expectTooltipNotVisible(wrapperOne);
3678
+ expectTooltipNotVisible(wrapperTwo);
3679
+ });
3680
+
3681
+ it("should render two connected charts when given same syncId", () => {
3682
+ const { container } = render(() => (
3683
+ <>
3684
+ <div id="barOne">
3685
+ <BarChart syncId={1} width={100} height={50} data={data}>
3686
+ <Bar dataKey="uv" />
3687
+ <Tooltip />
3688
+ </BarChart>
3689
+ </div>
3690
+ <div id="barTwo">
3691
+ <BarChart syncId={1} width={100} height={50} data={data}>
3692
+ <Bar dataKey="pv" />
3693
+ <Tooltip />
3694
+ </BarChart>
3695
+ </div>
3696
+ </>
3697
+ ));
3698
+
3699
+ const wrapperOne = container.querySelector("#barOne");
3700
+ assertNotNull(wrapperOne);
3701
+ const wrapperTwo = container.querySelector("#barTwo");
3702
+ assertNotNull(wrapperTwo);
3703
+
3704
+ expectTooltipNotVisible(wrapperOne);
3705
+ expectTooltipNotVisible(wrapperTwo);
3706
+
3707
+ // Hovering chart one makes BOTH show their own data (synchronised by index).
3708
+ showTooltipOnCoordinate(wrapperOne, barChartMouseHoverTooltipSelector, {
3709
+ clientX: 20,
3710
+ clientY: 20,
3711
+ });
3712
+ expectTooltipPayload(wrapperOne, "0", ["uv : 400"]);
3713
+ expectTooltipPayload(wrapperTwo, "0", ["pv : 2400"]);
3714
+
3715
+ hideTooltip(wrapperOne, barChartMouseHoverTooltipSelector);
3716
+ expectTooltipNotVisible(wrapperOne);
3717
+ expectTooltipNotVisible(wrapperTwo);
3718
+ });
3719
+ });