@solidports/recharts 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (306) hide show
  1. package/LICENSE +22 -0
  2. package/NOTICE +19 -0
  3. package/README.md +102 -0
  4. package/dist/dev.js +28564 -0
  5. package/dist/index.d.ts +7859 -0
  6. package/dist/index.js +28546 -0
  7. package/package.json +98 -0
  8. package/src/animation/AnimatedItems.tsx +183 -0
  9. package/src/animation/AnimationController.ts +33 -0
  10. package/src/animation/AnimationControllerImpl.ts +36 -0
  11. package/src/animation/AnimationHandle.ts +307 -0
  12. package/src/animation/CSSTransitionAnimate.tsx +170 -0
  13. package/src/animation/JavascriptAnimate.tsx +119 -0
  14. package/src/animation/easing.ts +221 -0
  15. package/src/animation/matchBy.ts +164 -0
  16. package/src/animation/timeoutController.ts +70 -0
  17. package/src/animation/useAnimationController.tsx +34 -0
  18. package/src/animation/useAnimationStartSnapshot.ts +118 -0
  19. package/src/animation/util.ts +41 -0
  20. package/src/cartesian/Area.tsx +915 -0
  21. package/src/cartesian/AreaRevealShape.tsx +190 -0
  22. package/src/cartesian/Bar.tsx +1369 -0
  23. package/src/cartesian/BarStack.tsx +152 -0
  24. package/src/cartesian/Brush.tsx +951 -0
  25. package/src/cartesian/CartesianAxis.tsx +722 -0
  26. package/src/cartesian/CartesianGrid.tsx +711 -0
  27. package/src/cartesian/ErrorBar.tsx +361 -0
  28. package/src/cartesian/Funnel.tsx +803 -0
  29. package/src/cartesian/GraphicalItemClipPath.tsx +67 -0
  30. package/src/cartesian/Line.tsx +863 -0
  31. package/src/cartesian/LineDrawShape.tsx +89 -0
  32. package/src/cartesian/ReferenceArea.tsx +331 -0
  33. package/src/cartesian/ReferenceDot.tsx +304 -0
  34. package/src/cartesian/ReferenceLine.tsx +474 -0
  35. package/src/cartesian/Scatter.tsx +888 -0
  36. package/src/cartesian/XAxis.tsx +433 -0
  37. package/src/cartesian/YAxis.tsx +443 -0
  38. package/src/cartesian/ZAxis.tsx +155 -0
  39. package/src/cartesian/cartesianPositionToCSSTranslate.tsx +29 -0
  40. package/src/cartesian/cartesianViewBoxToTrapezoid.tsx +21 -0
  41. package/src/cartesian/getCartesianPosition.tsx +267 -0
  42. package/src/cartesian/getEquidistantTicks.ts +144 -0
  43. package/src/cartesian/getTicks.ts +225 -0
  44. package/src/cartesian/isOutsidePosition.ts +15 -0
  45. package/src/cartesian/useAnimatedLineLength.ts +54 -0
  46. package/src/chart/AreaChart.tsx +29 -0
  47. package/src/chart/BarChart.tsx +29 -0
  48. package/src/chart/CartesianChart.tsx +131 -0
  49. package/src/chart/CategoricalChart.tsx +94 -0
  50. package/src/chart/ComposedChart.tsx +29 -0
  51. package/src/chart/FunnelChart.tsx +29 -0
  52. package/src/chart/LineChart.tsx +29 -0
  53. package/src/chart/PieChart.tsx +50 -0
  54. package/src/chart/PolarChart.tsx +164 -0
  55. package/src/chart/RadarChart.tsx +70 -0
  56. package/src/chart/RadialBarChart.tsx +46 -0
  57. package/src/chart/RechartsWrapper.tsx +551 -0
  58. package/src/chart/Sankey.tsx +1534 -0
  59. package/src/chart/ScatterChart.tsx +29 -0
  60. package/src/chart/SunburstChart.tsx +504 -0
  61. package/src/chart/Treemap.tsx +1223 -0
  62. package/src/chart/createInitialRootProps.ts +24 -0
  63. package/src/chart/types.ts +53 -0
  64. package/src/component/ActivePoints.tsx +144 -0
  65. package/src/component/Cell.tsx +37 -0
  66. package/src/component/Cursor.tsx +185 -0
  67. package/src/component/Customized.tsx +50 -0
  68. package/src/component/DefaultLegendContent.tsx +348 -0
  69. package/src/component/DefaultTooltipContent.tsx +224 -0
  70. package/src/component/Dots.tsx +157 -0
  71. package/src/component/Label.tsx +636 -0
  72. package/src/component/LabelList.tsx +375 -0
  73. package/src/component/Legend.tsx +512 -0
  74. package/src/component/ResponsiveContainer.tsx +348 -0
  75. package/src/component/Text.tsx +541 -0
  76. package/src/component/Tooltip.tsx +470 -0
  77. package/src/component/TooltipBoundingBox.tsx +146 -0
  78. package/src/component/responsiveContainerUtils.ts +134 -0
  79. package/src/container/ClipPathProvider.tsx +51 -0
  80. package/src/container/Layer.tsx +38 -0
  81. package/src/container/RootSurface.tsx +120 -0
  82. package/src/container/Surface.tsx +61 -0
  83. package/src/context/CellsContext.tsx +54 -0
  84. package/src/context/ErrorBarContext.tsx +146 -0
  85. package/src/context/GraphicalItemChildrenScope.tsx +18 -0
  86. package/src/context/PanoramaContext.tsx +9 -0
  87. package/src/context/RegisterGraphicalItemId.tsx +30 -0
  88. package/src/context/accessibilityContext.tsx +6 -0
  89. package/src/context/brushUpdateContext.tsx +9 -0
  90. package/src/context/chartDataContext.tsx +97 -0
  91. package/src/context/chartLayoutContext.tsx +201 -0
  92. package/src/context/legendPayloadContext.tsx +20 -0
  93. package/src/context/legendPortalContext.tsx +12 -0
  94. package/src/context/tooltipContext.tsx +89 -0
  95. package/src/context/tooltipPortalContext.tsx +12 -0
  96. package/src/context/useTooltipAxis.ts +22 -0
  97. package/src/hooks.ts +476 -0
  98. package/src/index.ts +280 -0
  99. package/src/polar/Pie.tsx +1360 -0
  100. package/src/polar/PolarAngleAxis.tsx +616 -0
  101. package/src/polar/PolarGrid.tsx +312 -0
  102. package/src/polar/PolarRadiusAxis.tsx +547 -0
  103. package/src/polar/Radar.tsx +734 -0
  104. package/src/polar/RadialBar.tsx +917 -0
  105. package/src/polar/defaultPolarAngleAxisProps.tsx +27 -0
  106. package/src/polar/defaultPolarRadiusAxisProps.tsx +25 -0
  107. package/src/shape/Cross.tsx +89 -0
  108. package/src/shape/Curve.tsx +343 -0
  109. package/src/shape/Dot.tsx +70 -0
  110. package/src/shape/Polygon.tsx +195 -0
  111. package/src/shape/Rectangle.tsx +470 -0
  112. package/src/shape/Sector.tsx +347 -0
  113. package/src/shape/Symbols.tsx +139 -0
  114. package/src/shape/Trapezoid.tsx +280 -0
  115. package/src/state/RechartsStateContext.tsx +12 -0
  116. package/src/state/RechartsStateProvider.tsx +87 -0
  117. package/src/state/RechartsStoreContext.tsx +25 -0
  118. package/src/state/RechartsStoreProvider.tsx +35 -0
  119. package/src/state/ReportChartProps.tsx +40 -0
  120. package/src/state/ReportEventSettings.tsx +30 -0
  121. package/src/state/ReportMainChartProps.tsx +61 -0
  122. package/src/state/ReportPolarOptions.tsx +35 -0
  123. package/src/state/SetGraphicalItem.ts +79 -0
  124. package/src/state/SetLegendPayload.ts +134 -0
  125. package/src/state/SetTooltipEntrySettings.tsx +72 -0
  126. package/src/state/actions.ts +464 -0
  127. package/src/state/brushSlice.ts +13 -0
  128. package/src/state/cartesianAxisSlice.ts +141 -0
  129. package/src/state/chartDataSlice.ts +50 -0
  130. package/src/state/chartState.ts +297 -0
  131. package/src/state/errorBarSlice.ts +29 -0
  132. package/src/state/eventSettingsSlice.ts +8 -0
  133. package/src/state/events.ts +76 -0
  134. package/src/state/externalEventsMiddleware.ts +255 -0
  135. package/src/state/graphicalItemsSlice.ts +74 -0
  136. package/src/state/hooks/useChartSelectors.tsx +45 -0
  137. package/src/state/keyboardEventsMiddleware.ts +228 -0
  138. package/src/state/layoutSlice.ts +21 -0
  139. package/src/state/legendSlice.ts +57 -0
  140. package/src/state/mouseEventsMiddleware.ts +185 -0
  141. package/src/state/optionsSlice.ts +47 -0
  142. package/src/state/polarAxisSlice.ts +10 -0
  143. package/src/state/polarOptionsSlice.ts +12 -0
  144. package/src/state/rawData.ts +26 -0
  145. package/src/state/referenceElementsSlice.ts +40 -0
  146. package/src/state/renderedTicksSlice.ts +15 -0
  147. package/src/state/rootPropsSlice.ts +47 -0
  148. package/src/state/selectors/areaSelectors.ts +240 -0
  149. package/src/state/selectors/arrayEqualityCheck.ts +29 -0
  150. package/src/state/selectors/axisSelectors.ts +2157 -0
  151. package/src/state/selectors/barSelectors.ts +310 -0
  152. package/src/state/selectors/barStackSelectors.ts +77 -0
  153. package/src/state/selectors/brushSelectors.ts +33 -0
  154. package/src/state/selectors/chartSelector.ts +185 -0
  155. package/src/state/selectors/combiners/combineActiveLabel.ts +16 -0
  156. package/src/state/selectors/combiners/combineActiveTooltipIndex.ts +95 -0
  157. package/src/state/selectors/combiners/combineAllBarPositions.ts +122 -0
  158. package/src/state/selectors/combiners/combineAxisRangeWithReverse.ts +16 -0
  159. package/src/state/selectors/combiners/combineBarPosition.ts +23 -0
  160. package/src/state/selectors/combiners/combineBarSizeList.ts +80 -0
  161. package/src/state/selectors/combiners/combineCheckedDomain.ts +48 -0
  162. package/src/state/selectors/combiners/combineConfiguredScale.ts +111 -0
  163. package/src/state/selectors/combiners/combineCoordinateForDefaultIndex.ts +45 -0
  164. package/src/state/selectors/combiners/combineDisplayedStackedData.ts +50 -0
  165. package/src/state/selectors/combiners/combineInverseScaleFunction.ts +16 -0
  166. package/src/state/selectors/combiners/combineRealScaleType.ts +44 -0
  167. package/src/state/selectors/combiners/combineStackedData.ts +27 -0
  168. package/src/state/selectors/combiners/combineTooltipInteractionState.ts +86 -0
  169. package/src/state/selectors/combiners/combineTooltipPayload.ts +205 -0
  170. package/src/state/selectors/combiners/combineTooltipPayloadConfigurations.ts +58 -0
  171. package/src/state/selectors/containerSelectors.ts +12 -0
  172. package/src/state/selectors/dataSelectors.ts +88 -0
  173. package/src/state/selectors/funnelSelectors.ts +75 -0
  174. package/src/state/selectors/graphicalItemSelectors.ts +30 -0
  175. package/src/state/selectors/legendSelectors.ts +29 -0
  176. package/src/state/selectors/lineSelectors.ts +134 -0
  177. package/src/state/selectors/numberDomainEqualityCheck.ts +14 -0
  178. package/src/state/selectors/pickAxisId.ts +5 -0
  179. package/src/state/selectors/pickAxisType.ts +3 -0
  180. package/src/state/selectors/pieSelectors.ts +97 -0
  181. package/src/state/selectors/polarAxisSelectors.ts +201 -0
  182. package/src/state/selectors/polarGridSelectors.ts +28 -0
  183. package/src/state/selectors/polarScaleSelectors.ts +133 -0
  184. package/src/state/selectors/polarSelectors.ts +219 -0
  185. package/src/state/selectors/radarSelectors.ts +191 -0
  186. package/src/state/selectors/radialBarSelectors.ts +435 -0
  187. package/src/state/selectors/rootPropsSelectors.ts +25 -0
  188. package/src/state/selectors/scatterSelectors.ts +96 -0
  189. package/src/state/selectors/selectActivePropsFromChartPointer.ts +26 -0
  190. package/src/state/selectors/selectAllAxes.ts +17 -0
  191. package/src/state/selectors/selectChartOffset.ts +16 -0
  192. package/src/state/selectors/selectChartOffsetInternal.ts +136 -0
  193. package/src/state/selectors/selectLegendArea.ts +20 -0
  194. package/src/state/selectors/selectPlotArea.ts +22 -0
  195. package/src/state/selectors/selectTooltipAxisId.ts +7 -0
  196. package/src/state/selectors/selectTooltipAxisType.ts +32 -0
  197. package/src/state/selectors/selectTooltipEventType.ts +48 -0
  198. package/src/state/selectors/selectTooltipPayloadSearcher.ts +6 -0
  199. package/src/state/selectors/selectTooltipSettings.ts +39 -0
  200. package/src/state/selectors/selectTooltipState.ts +8 -0
  201. package/src/state/selectors/selectors.ts +271 -0
  202. package/src/state/selectors/tooltipSelectors.ts +578 -0
  203. package/src/state/selectors/touchSelectors.ts +31 -0
  204. package/src/state/store.ts +29 -0
  205. package/src/state/storeIdentity.ts +9 -0
  206. package/src/state/teardownWrite.ts +10 -0
  207. package/src/state/tooltipInteraction.ts +23 -0
  208. package/src/state/tooltipSlice.ts +334 -0
  209. package/src/state/touchEventsMiddleware.ts +214 -0
  210. package/src/state/types/AnimationSettings.ts +20 -0
  211. package/src/state/types/AreaSettings.ts +14 -0
  212. package/src/state/types/BarSettings.ts +15 -0
  213. package/src/state/types/LineSettings.ts +9 -0
  214. package/src/state/types/PieSettings.ts +34 -0
  215. package/src/state/types/RadarSettings.ts +5 -0
  216. package/src/state/types/RadialBarSettings.ts +10 -0
  217. package/src/state/types/ScatterSettings.ts +12 -0
  218. package/src/state/types/StackedGraphicalItem.ts +34 -0
  219. package/src/state/useChartState.ts +17 -0
  220. package/src/state/zIndexSlice.ts +39 -0
  221. package/src/synchronisation/syncSelectors.ts +7 -0
  222. package/src/synchronisation/types.ts +44 -0
  223. package/src/synchronisation/useChartSynchronisation.tsx +404 -0
  224. package/src/theme/RechartsTheme.ts +16 -0
  225. package/src/theme/RechartsThemeContext.ts +19 -0
  226. package/src/theme/darkTheme.ts +13 -0
  227. package/src/theme/graphicalItemIdentity.ts +70 -0
  228. package/src/theme/legacyTheme.ts +17 -0
  229. package/src/theme/lightTheme.ts +13 -0
  230. package/src/types.ts +54 -0
  231. package/src/util/ActiveShapeUtils.tsx +162 -0
  232. package/src/util/BarUtils.tsx +62 -0
  233. package/src/util/BarePortal.tsx +50 -0
  234. package/src/util/CamelCaseSVGAttrs.ts +34 -0
  235. package/src/util/CartesianUtils.ts +48 -0
  236. package/src/util/ChartUtils.ts +802 -0
  237. package/src/util/Constants.ts +42 -0
  238. package/src/util/CssPrefixUtils.ts +20 -0
  239. package/src/util/DOMUtils.ts +129 -0
  240. package/src/util/DataUtils.ts +216 -0
  241. package/src/util/Events.ts +16 -0
  242. package/src/util/FunnelUtils.tsx +15 -0
  243. package/src/util/Global.ts +12 -0
  244. package/src/util/IfOverflow.ts +15 -0
  245. package/src/util/LRUCache.ts +41 -0
  246. package/src/util/LogUtils.ts +22 -0
  247. package/src/util/PolarUtils.ts +132 -0
  248. package/src/util/RadialBarUtils.tsx +24 -0
  249. package/src/util/ReactUtils.ts +95 -0
  250. package/src/util/ReduceCSSCalc.ts +187 -0
  251. package/src/util/ScatterUtils.tsx +52 -0
  252. package/src/util/ShapeElementProps.tsx +87 -0
  253. package/src/util/TickUtils.ts +60 -0
  254. package/src/util/XAxisUtils.ts +48 -0
  255. package/src/util/YAxisUtils.ts +48 -0
  256. package/src/util/axisPropsAreEqual.ts +48 -0
  257. package/src/util/createCartesianCharts.tsx +150 -0
  258. package/src/util/createEventProxy.ts +20 -0
  259. package/src/util/createPolarCharts.tsx +112 -0
  260. package/src/util/cursor/getCursorPoints.ts +46 -0
  261. package/src/util/cursor/getCursorRectangle.ts +28 -0
  262. package/src/util/cursor/getRadialCursorPoints.ts +32 -0
  263. package/src/util/excludeEventProps.ts +171 -0
  264. package/src/util/getActiveCoordinate.ts +213 -0
  265. package/src/util/getAxisTypeBasedOnLayout.ts +21 -0
  266. package/src/util/getClassNameFromUnknown.ts +6 -0
  267. package/src/util/getEveryNth.ts +27 -0
  268. package/src/util/getRadiusAndStrokeWidthFromDot.ts +35 -0
  269. package/src/util/getRelativeCoordinate.ts +80 -0
  270. package/src/util/getSliced.ts +13 -0
  271. package/src/util/hoverDedupe.ts +41 -0
  272. package/src/util/isDomainSpecifiedByUser.ts +219 -0
  273. package/src/util/isWellBehavedNumber.ts +7 -0
  274. package/src/util/pathTotalLength.ts +25 -0
  275. package/src/util/payload/getUniqPayload.ts +28 -0
  276. package/src/util/propsAreEqual.ts +121 -0
  277. package/src/util/resolveDefaultProps.ts +161 -0
  278. package/src/util/round.ts +32 -0
  279. package/src/util/scale/CartesianScaleHelper.ts +72 -0
  280. package/src/util/scale/CustomScaleDefinition.ts +81 -0
  281. package/src/util/scale/RechartsScale.ts +130 -0
  282. package/src/util/scale/createCategoricalInverse.ts +72 -0
  283. package/src/util/scale/getNiceTickValues.ts +311 -0
  284. package/src/util/scale/index.ts +2 -0
  285. package/src/util/scale/util/arithmetic.ts +54 -0
  286. package/src/util/solid-1-compat.ts +310 -0
  287. package/src/util/solidJsxCamelAugment.d.ts +84 -0
  288. package/src/util/stacks/getStackSeriesIdentifier.ts +21 -0
  289. package/src/util/stacks/stackTypes.ts +60 -0
  290. package/src/util/structurallyEqual.ts +31 -0
  291. package/src/util/svgPropertiesAndEvents.ts +53 -0
  292. package/src/util/svgPropertiesNoEvents.ts +571 -0
  293. package/src/util/tooltip/translate.ts +171 -0
  294. package/src/util/typedDataKey.ts +48 -0
  295. package/src/util/types.ts +1560 -0
  296. package/src/util/useAnimationId.ts +31 -0
  297. package/src/util/useElementOffset.ts +110 -0
  298. package/src/util/useId.ts +8 -0
  299. package/src/util/usePrefersReducedMotion.ts +48 -0
  300. package/src/util/useReportScale.ts +24 -0
  301. package/src/util/useUniqueId.ts +30 -0
  302. package/src/zIndex/DefaultZIndexes.ts +84 -0
  303. package/src/zIndex/ZIndexLayer.tsx +121 -0
  304. package/src/zIndex/ZIndexPortal.tsx +79 -0
  305. package/src/zIndex/getZIndexFromUnknown.ts +14 -0
  306. package/src/zIndex/zIndexSelectors.ts +48 -0
@@ -0,0 +1,1360 @@
1
+ /* eslint-disable import/no-cycle, sort-keys */
2
+ import type { JSX } from '@solidjs/web';
3
+ import { createHoverDedupe } from "../util/hoverDedupe"
4
+ import { createMemo, For, Show, untrack, useContext } from 'solid-js';
5
+ import get from "es-toolkit/compat/get"
6
+
7
+ import { clsx } from "clsx"
8
+ import { selectPieLegend, selectPieSectors } from "../state/selectors/pieSelectors"
9
+ import { useChartStore } from "../state/RechartsStoreContext"
10
+ import { CellsContextProvider, createCellsRegistry } from "../context/CellsContext"
11
+ import { Layer } from "../container/Layer"
12
+ import { Curve, Props as CurveProps } from "../shape/Curve"
13
+ import { Text } from "../component/Text"
14
+ import { getMaxRadius, polarToCartesian } from "../util/PolarUtils"
15
+ import { getPercentValue, interpolate, isNumber, mathSign } from "../util/DataUtils"
16
+ import { getTooltipNameProp, getValueByDataKey } from "../util/ChartUtils"
17
+ import {
18
+ ActiveShape,
19
+ adaptEventsOfChild,
20
+ AnimationDuration,
21
+ AnimationTiming,
22
+ ChartOffsetInternal,
23
+ Coordinate,
24
+ DataConsumer,
25
+ DataKey,
26
+ DataProvider,
27
+ GeometrySector,
28
+ LegendType,
29
+ PresentationAttributesAdaptChildEvent,
30
+ TooltipType,
31
+ } from "../util/types"
32
+ import { Shape } from "../util/ActiveShapeUtils"
33
+ import {
34
+ TooltipTriggerInfo,
35
+ useMouseClickItemDispatch,
36
+ useMouseEnterItemDispatch,
37
+ useMouseLeaveItemDispatch,
38
+ } from "../context/tooltipContext"
39
+ import { TooltipPayload, TooltipPayloadConfiguration } from "../state/tooltipSlice"
40
+ import { SetTooltipEntrySettings } from "../state/SetTooltipEntrySettings"
41
+ import {
42
+ selectActiveTooltipDataKey,
43
+ selectActiveTooltipGraphicalItemId,
44
+ selectActiveTooltipIndex,
45
+ } from "../state/selectors/tooltipSelectors"
46
+ import { SetPolarLegendPayload } from "../state/SetLegendPayload"
47
+ import {
48
+ DATA_ITEM_GRAPHICAL_ITEM_ID_ATTRIBUTE_NAME,
49
+ DATA_ITEM_INDEX_ATTRIBUTE_NAME,
50
+ } from "../util/Constants"
51
+ import { RequiresDefaultProps, resolveDefaultProps } from "../util/resolveDefaultProps"
52
+ import { RegisterGraphicalItemId } from "../context/RegisterGraphicalItemId"
53
+ import { SetPolarGraphicalItem } from "../state/SetGraphicalItem"
54
+ import { RechartsStateContext } from "../state/RechartsStateContext"
55
+ import { PiePresentationProps, PieSettings } from "../state/types/PieSettings"
56
+ import {
57
+ svgPropertiesNoEvents,
58
+ svgPropertiesNoEventsFromUnknown,
59
+ SVGPropsNoEvents,
60
+ } from "../util/svgPropertiesNoEvents"
61
+ import { AnimatedItems, useAnimationCallbacks } from "../animation/AnimatedItems"
62
+ import type { AnimationInterpolateFn } from "../animation/AnimatedItems"
63
+ import { matchAppend } from "../animation/matchBy"
64
+ import type { AnimationMatchByProp } from "../animation/matchBy"
65
+ import { usePolarChartLayout } from "../context/chartLayoutContext"
66
+ import type { PolarLayout, ShapeAnimationProps } from "../util/types"
67
+ import {
68
+ LabelListContextBridge,
69
+ LabelListFromLabelProp,
70
+ PolarLabelListContextProvider,
71
+ PolarLabelListEntry,
72
+ Props as LabelListProps,
73
+ } from "../component/LabelList"
74
+ import { PolarLabelContextProvider } from "../component/Label"
75
+ import { GraphicalItemId } from "../state/graphicalItemsSlice"
76
+ import { ZIndexable, ZIndexLayer } from "../zIndex/ZIndexLayer"
77
+ import { DefaultZIndexes } from "../zIndex/DefaultZIndexes"
78
+ import { ChartData } from "../state/chartDataSlice"
79
+ import { getClassNameFromUnknown } from "../util/getClassNameFromUnknown"
80
+ import { cloneJsxNodeWithProps, isJsxNode } from "../util/ReactUtils"
81
+ import type { Formatter } from "../component/DefaultTooltipContent"
82
+
83
+ import { mergeProps, splitProps } from '../util/solid-1-compat';
84
+ interface PieDef {
85
+ /**
86
+ * The x-coordinate of center. If set a percentage, the final value is obtained by multiplying the percentage of container width.
87
+ */
88
+ cx?: number | string
89
+ /**
90
+ * The y-coordinate of center. If set a percentage, the final value is obtained by multiplying the percentage of container height.
91
+ */
92
+ cy?: number | string
93
+ /**
94
+ * Angle in degrees from which the chart should start.
95
+ */
96
+ startAngle?: number
97
+ /**
98
+ * Angle, in degrees, at which the chart should end.
99
+ */
100
+ endAngle?: number
101
+ /**
102
+ * The angle between two sectors.
103
+ *
104
+ * @example <Pie paddingAngle={5} />
105
+ * @example https://recharts.github.io/examples/PieChartWithPaddingAngle
106
+ */
107
+ paddingAngle?: number
108
+ /**
109
+ * The inner radius of the sectors.
110
+ * If set a percentage, the final value is obtained by multiplying the percentage of maxRadius which is calculated by the width, height, cx, cy.
111
+ */
112
+ innerRadius?: number | string
113
+ /**
114
+ * The outer radius of the sectors.
115
+ * If set a percentage, the final value is obtained by multiplying the percentage of maxRadius which is calculated by the width, height, cx, cy.
116
+ * Function should return a string percentage or number.
117
+ */
118
+ outerRadius?: number | string | ((dataPoint: unknown) => number | string)
119
+ cornerRadius?: number | string
120
+ }
121
+
122
+ type PieLabelLine =
123
+ | ((props: Record<string, unknown>) => JSX.Element)
124
+ | JSX.PathSVGAttributes<SVGPathElement>
125
+ | boolean
126
+
127
+ interface PieLabelExtraProps {
128
+ stroke: string
129
+ index: number
130
+ textAnchor: string
131
+ }
132
+
133
+ export type PieLabelRenderProps = Omit<SVGPropsNoEvents<PieSvgAttributes>, "offset"> &
134
+ Omit<PieSectorDataItem, "offset"> &
135
+ PieLabelExtraProps &
136
+ Coordinate
137
+
138
+ export type LabelListPropsWithPosition = LabelListProps & { position: LabelListProps["position"] }
139
+
140
+ /**
141
+ * The `label` prop in Pie accepts a variety of alternatives.
142
+ */
143
+ export type PieLabel =
144
+ | boolean
145
+ | LabelListPropsWithPosition
146
+ | Partial<PieLabelRenderProps>
147
+ | ((props: PieLabelRenderProps) => JSX.Element)
148
+
149
+ export type PieSectorData = GeometrySector &
150
+ TooltipTriggerInfo & {
151
+ dataKey?: DataKey<unknown>
152
+ midAngle?: number
153
+ middleRadius?: number
154
+ name?: string | number
155
+ paddingAngle?: number
156
+ payload?: unknown
157
+ percent?: number
158
+ value: number
159
+ }
160
+
161
+ /**
162
+ * We spread the data object into the sector data item,
163
+ * so we can't really know what is going to be inside.
164
+ *
165
+ * This type represents our best effort, but it all depends on the input data
166
+ * and what is inside of it.
167
+ *
168
+ * https://github.com/recharts/recharts/issues/6380
169
+ * https://github.com/recharts/recharts/discussions/6375
170
+ */
171
+ export type PieSectorDataItem = PiePresentationProps &
172
+ PieCoordinate &
173
+ PieSectorData & {
174
+ cornerRadius: number | undefined
175
+ }
176
+
177
+ export type PieSectorShapeProps = PieSectorDataItem & { isActive: boolean; index: number }
178
+ export type PieShape = JSX.Element | ((props: PieSectorShapeProps, index: number) => JSX.Element)
179
+
180
+ interface PieEvents {
181
+ /**
182
+ * The customized event handler of click on the sectors in this group.
183
+ */
184
+ onClick?: (data: PieSectorDataItem, index: number, e: MouseEvent & { currentTarget: SVGGraphicsElement }) => void
185
+ /**
186
+ * The customized event handler of mousedown on the sectors in this group.
187
+ */
188
+ onMouseDown?: (data: PieSectorDataItem, index: number, e: MouseEvent & { currentTarget: SVGGraphicsElement }) => void
189
+ /**
190
+ * The customized event handler of mouseup on the sectors in this group.
191
+ */
192
+ onMouseUp?: (data: PieSectorDataItem, index: number, e: MouseEvent & { currentTarget: SVGGraphicsElement }) => void
193
+ /**
194
+ * The customized event handler of mousemove on the sectors in this group.
195
+ */
196
+ onMouseMove?: (data: PieSectorDataItem, index: number, e: MouseEvent & { currentTarget: SVGGraphicsElement }) => void
197
+ /**
198
+ * The customized event handler of mouseover on the sectors in this group.
199
+ */
200
+ onMouseOver?: (data: PieSectorDataItem, index: number, e: MouseEvent & { currentTarget: SVGGraphicsElement }) => void
201
+ /**
202
+ * The customized event handler of mouseout on the sectors in this group.
203
+ */
204
+ onMouseOut?: (data: PieSectorDataItem, index: number, e: MouseEvent & { currentTarget: SVGGraphicsElement }) => void
205
+ /**
206
+ * The customized event handler of mouseenter on the sectors in this group.
207
+ */
208
+ onMouseEnter?: (data: PieSectorDataItem, index: number, e: MouseEvent & { currentTarget: SVGGraphicsElement }) => void
209
+ /**
210
+ * The customized event handler of mouseleave on the sectors in this group.
211
+ */
212
+ onMouseLeave?: (data: PieSectorDataItem, index: number, e: MouseEvent & { currentTarget: SVGGraphicsElement }) => void
213
+ onTouchStart?: (data: PieSectorDataItem, index: number, e: TouchEvent & { currentTarget: SVGGraphicsElement }) => void
214
+ onTouchMove?: (data: PieSectorDataItem, index: number, e: TouchEvent & { currentTarget: SVGGraphicsElement }) => void
215
+ onTouchEnd?: (data: PieSectorDataItem, index: number, e: TouchEvent & { currentTarget: SVGGraphicsElement }) => void
216
+ }
217
+
218
+ /**
219
+ * Internal props, combination of external props + defaultProps + private Recharts state
220
+ */
221
+ interface InternalPieProps<DataPointType = unknown>
222
+ extends DataProvider<DataPointType>, PieDef, ZIndexable, PieEvents {
223
+ id: GraphicalItemId
224
+ className?: string
225
+ name?: string | number
226
+ dataKey: DataKey<DataPointType, unknown>
227
+ nameKey?: DataKey<DataPointType, string>
228
+ /** The minimum angle for no-zero element */
229
+ minAngle?: number
230
+ legendType?: LegendType
231
+ tooltipType?: TooltipType
232
+ formatter?: Formatter
233
+ /** the max radius of pie */
234
+ maxRadius?: number
235
+ hide?: boolean
236
+ sectors: ReadonlyArray<PieSectorDataItem>
237
+ /** @deprecated */
238
+ activeShape?: ActiveShape<PieSectorDataItem>
239
+ /** @deprecated */
240
+ inactiveShape?: ActiveShape<PieSectorDataItem>
241
+ shape?: PieShape
242
+ labelLine?: PieLabelLine
243
+ label?: PieLabel
244
+ animationEasing: AnimationTiming
245
+ animationInterpolateFn: AnimationInterpolateFn<PieSectorDataItem, PolarLayout>
246
+ animationMatchBy: AnimationMatchByProp<PieSectorDataItem>
247
+ isAnimationActive: boolean | "auto"
248
+ animationBegin: number
249
+ animationDuration: AnimationDuration
250
+ onAnimationStart?: () => void
251
+ onAnimationEnd?: () => void
252
+ rootTabIndex?: number
253
+ }
254
+
255
+ interface PieProps<DataPointType = unknown, DataValueType = unknown>
256
+ extends
257
+ DataProvider<DataPointType>,
258
+ DataConsumer<DataPointType, DataValueType>,
259
+ PieDef,
260
+ PieEvents,
261
+ ZIndexable {
262
+ /**
263
+ * This component is rendered when this graphical item is activated
264
+ * (could be by mouse hover, touch, keyboard, programmatically).
265
+ *
266
+ * @deprecated Use the `shape` prop to create each sector. `isActive` designates the "active" shape.
267
+ * @example <Pie activeShape={<CustomActiveShape />} />
268
+ * @example https://recharts.github.io/examples/CustomActiveShapePieChart
269
+ */
270
+ activeShape?: ActiveShape<PieSectorDataItem>
271
+ /**
272
+ * Specifies when the animation should begin, the unit of this option is ms.
273
+ * @defaultValue 400
274
+ */
275
+ animationBegin?: number
276
+ /**
277
+ * Specifies the duration of animation, the unit of this option is ms.
278
+ * @defaultValue 1500
279
+ */
280
+ animationDuration?: AnimationDuration
281
+ /**
282
+ * The type of easing function.
283
+ * @defaultValue ease
284
+ */
285
+ animationEasing?: AnimationTiming
286
+ /**
287
+ * Custom animation function for interpolating data items.
288
+ * When provided, this replaces the default animation interpolation.
289
+ *
290
+ * @since 3.9
291
+ * @see {@link https://recharts.github.io/en-US/guide/animations/ Animations guide}
292
+ */
293
+ animationInterpolateFn?: AnimationInterpolateFn<PieSectorDataItem, PolarLayout>
294
+ /**
295
+ * Strategy for matching previous items to next items during animation.
296
+ *
297
+ * - `matchAppend` (default): match sequentially by index and treat newly appended items as new
298
+ * - `matchByIndex`: match by array position with proportional stretching
299
+ * - `matchByDataKey('someKey')`: match by a data key from the payload
300
+ * - Custom function `(item, index) => key`: match by the returned key
301
+ *
302
+ * @defaultValue append
303
+ */
304
+ animationMatchBy?: AnimationMatchByProp<PieSectorDataItem>
305
+ className?: string
306
+ /**
307
+ * Hides the whole graphical element when true.
308
+ *
309
+ * Hiding an element is different from removing it from the chart:
310
+ * Hidden graphical elements are still visible in Legend,
311
+ * and can be included in axis domain calculations,
312
+ * depending on `includeHidden` props of your XAxis/YAxis.
313
+ *
314
+ * @defaultValue false
315
+ */
316
+ hide?: boolean
317
+ id?: string
318
+ /**
319
+ * The shape of inactive sector.
320
+ * @deprecated Use the `shape` prop to modify each sector.
321
+ */
322
+ inactiveShape?: ActiveShape<PieSectorDataItem>
323
+ /**
324
+ * If set false, animation will be disabled.
325
+ * If set "auto", animation is disabled during SSR and when the user prefers reduced motion.
326
+ * @defaultValue auto
327
+ */
328
+ isAnimationActive?: boolean | "auto"
329
+ /**
330
+ * Renders one label for each pie sector. Options:
331
+ * - `true`: renders default labels;
332
+ * - `false`: no labels are rendered;
333
+ * - `object` that has `position` prop: the props of LabelList component;
334
+ * - `object` that does not have `position` prop: the props of a custom Pie label (similar to Label with position "outside"); this variant supports `labelLine`
335
+ * - `Element`: a custom label element;
336
+ * - `function`: a render function of custom label.
337
+ *
338
+ * Also see the `labelLine` prop that draws a line connecting each label to the corresponding sector.
339
+ *
340
+ * @defaultValue false
341
+ * @example <Pie label={<CustomizedLabel />} />
342
+ * @example https://recharts.github.io/examples/PieChartWithCustomizedLabel
343
+ */
344
+ label?: PieLabel
345
+ /**
346
+ * If false set, label lines will not be drawn. If true set, label lines will be drawn which have the props calculated internally.
347
+ * If object set, label lines will be drawn which have the props merged by the internal calculated props and the option.
348
+ * If set a function, the function will be called to render customized label line.
349
+ * @defaultValue true
350
+ * @example <Pie labelLine={<CustomizedLabelLine />} />
351
+ * @example https://recharts.github.io/examples/PieChartWithCustomizedLabel
352
+ */
353
+ labelLine?: PieLabelLine
354
+ /**
355
+ * The type of icon in legend. If set to 'none', no legend item will be rendered.
356
+ * @defaultValue rect
357
+ */
358
+ legendType?: LegendType
359
+ /** the max radius of pie */
360
+ maxRadius?: number
361
+ /**
362
+ * The minimum angle of each unzero data.
363
+ * @defaultValue 0
364
+ */
365
+ minAngle?: number
366
+ /**
367
+ * The name of this graphical item, used in tooltip and legend.
368
+ */
369
+ name?: string | number
370
+ /**
371
+ * Name represents each sector in the tooltip, and legend.
372
+ * This allows you to extract the name from the data:
373
+ *
374
+ * - `string`: the name of the field in the data object;
375
+ * - `number`: the index of the field in the data;
376
+ * - `function`: a function that receives the data object and returns the name.
377
+ *
378
+ * @defaultValue name
379
+ */
380
+ nameKey?: DataKey<DataPointType, DataValueType>
381
+ /**
382
+ * The customized event handler of animation end.
383
+ */
384
+ onAnimationEnd?: () => void
385
+ /**
386
+ * The customized event handler of animation start.
387
+ */
388
+ onAnimationStart?: () => void
389
+ /**
390
+ * The tabindex of wrapper surrounding the cells.
391
+ * @defaultValue 0
392
+ */
393
+ rootTabIndex?: number
394
+ /**
395
+ * The custom shape of a Pie Sector.
396
+ * Can also be used to render active sector by checking isActive.
397
+ * If undefined, renders Sector shape.
398
+ */
399
+ shape?: PieShape
400
+ tooltipType?: TooltipType
401
+ /**
402
+ * Formats the value displayed in the tooltip for this Pie.
403
+ * When set, takes precedence over the `formatter` prop on the Tooltip component.
404
+ */
405
+ formatter?: Formatter
406
+ /**
407
+ * @defaultValue 100
408
+ */
409
+ zIndex?: number
410
+ }
411
+
412
+ type PieSvgAttributes = Omit<
413
+ PresentationAttributesAdaptChildEvent<unknown, SVGElement>,
414
+ "ref" | keyof PieEvents
415
+ >
416
+
417
+ type InternalProps = PieSvgAttributes & InternalPieProps
418
+
419
+ /* eslint-disable-next-line typescript-eslint/no-explicit-any -- upstream contract: untyped items accept any data */
420
+ export type Props<DataPointType = any, DataValueType = any> = PieSvgAttributes & PieProps<DataPointType, DataValueType>
421
+
422
+ type RealPieData = Record<string, unknown>
423
+
424
+ export type PieCoordinate = {
425
+ cx: number
426
+ cy: number
427
+ innerRadius: number
428
+ outerRadius: number
429
+ maxRadius: number
430
+ }
431
+
432
+ function SetPiePayloadLegend(props: { children?: JSX.Element; id: GraphicalItemId }): JSX.Element {
433
+ const ctx = useChartStore()
434
+ /* Solid does not support React.Children iteration; cells passed as undefined */
435
+ const legendPayload = createMemo(() =>
436
+ ctx ? selectPieLegend(ctx.store, props.id, undefined) : undefined,
437
+ )
438
+ return (
439
+ <Show when={legendPayload()}>
440
+ {(payload) => <SetPolarLegendPayload legendPayload={payload()} />}
441
+ </Show>
442
+ )
443
+ }
444
+
445
+ type PieSectorsProps = ShapeAnimationProps & {
446
+ sectors: Readonly<PieSectorDataItem[]>
447
+ /**
448
+ * @deprecated
449
+ */
450
+ activeShape: ActiveShape<Readonly<PieSectorDataItem>> | undefined
451
+ /**
452
+ * @deprecated
453
+ */
454
+ inactiveShape: ActiveShape<Readonly<PieSectorDataItem>> | undefined
455
+ shape: PieShape
456
+ allOtherPieProps: WithoutId<InternalProps>
457
+ id: GraphicalItemId
458
+ }
459
+
460
+ function getActiveShapeFill(
461
+ activeShape: ActiveShape<Readonly<PieSectorDataItem>> | undefined,
462
+ ): string | undefined {
463
+ /* activeShape can be boolean/function/element/object; only element/object can carry a static fill value. */
464
+ if (activeShape == null || typeof activeShape === "boolean" || typeof activeShape === "function") {
465
+ return undefined
466
+ }
467
+ if (isJsxNode(activeShape)) {
468
+ /* Solid element form: the evaluated node carries `fill` as an attribute. */
469
+ const fill = activeShape instanceof Element ? activeShape.getAttribute("fill") : null
470
+ return fill ?? undefined
471
+ }
472
+ const { fill } = activeShape as { fill?: unknown }
473
+ return typeof fill === "string" ? fill : undefined
474
+ }
475
+
476
+ function SetPieTooltipEntrySettings(
477
+ props: Pick<
478
+ InternalProps,
479
+ | "activeShape"
480
+ | "dataKey"
481
+ | "nameKey"
482
+ | "sectors"
483
+ | "stroke"
484
+ | "strokeWidth"
485
+ | "fill"
486
+ | "name"
487
+ | "hide"
488
+ | "tooltipType"
489
+ | "formatter"
490
+ | "id"
491
+ >,
492
+ ): JSX.Element {
493
+ /* GOTCHA-005: createMemo so reactive props flow into the settings object. */
494
+ const tooltipEntrySettings = createMemo<TooltipPayloadConfiguration>(() => {
495
+ const activeShapeFill = getActiveShapeFill(props.activeShape)
496
+ return {
497
+ dataDefinedOnItem: props.sectors.map((sector: PieSectorDataItem) => {
498
+ const sectorTooltipPayload = sector.tooltipPayload
499
+ if (activeShapeFill == null || sectorTooltipPayload == null) {
500
+ return sectorTooltipPayload
501
+ }
502
+ return sectorTooltipPayload.map((item) => ({
503
+ ...item,
504
+ color: activeShapeFill,
505
+ fill: activeShapeFill,
506
+ }))
507
+ }),
508
+ getPosition: (index) => props.sectors[Number(index)]?.tooltipPosition,
509
+ settings: {
510
+ color: props.fill,
511
+ dataKey: props.dataKey,
512
+ fill: props.fill,
513
+ formatter: props.formatter,
514
+ graphicalItemId: props.id,
515
+ hide: props.hide,
516
+ name: getTooltipNameProp(props.name, props.dataKey),
517
+ nameKey: props.nameKey,
518
+ stroke: props.stroke,
519
+ strokeWidth: props.strokeWidth,
520
+ type: props.tooltipType,
521
+ unit: "",
522
+ },
523
+ }
524
+ })
525
+ return <SetTooltipEntrySettings tooltipEntrySettings={tooltipEntrySettings()} />
526
+ }
527
+
528
+ const getTextAnchor = (x: number, cx: number) => {
529
+ if (x > cx) {
530
+ return "start"
531
+ }
532
+ if (x < cx) {
533
+ return "end"
534
+ }
535
+
536
+ return "middle"
537
+ }
538
+
539
+ const getOuterRadius = (
540
+ dataPoint: unknown,
541
+ outerRadius: number | string | ((element: unknown) => number | string),
542
+ maxPieRadius: number,
543
+ ) => {
544
+ if (typeof outerRadius === "function") {
545
+ return getPercentValue(outerRadius(dataPoint), maxPieRadius, maxPieRadius * 0.8)
546
+ }
547
+ return getPercentValue(outerRadius, maxPieRadius, maxPieRadius * 0.8)
548
+ }
549
+
550
+ const parseCoordinateOfPie = (
551
+ pieSettings: PieSettings,
552
+ offset: ChartOffsetInternal,
553
+ dataPoint: unknown,
554
+ ): PieCoordinate => {
555
+ const { top, left, width, height } = offset
556
+ const maxPieRadius = getMaxRadius(width, height)
557
+ const cx = left + getPercentValue(pieSettings.cx, width, width / 2)
558
+ const cy = top + getPercentValue(pieSettings.cy, height, height / 2)
559
+ const innerRadius = getPercentValue(pieSettings.innerRadius, maxPieRadius, 0)
560
+
561
+ const outerRadius = getOuterRadius(dataPoint, pieSettings.outerRadius, maxPieRadius)
562
+
563
+ const maxRadius = pieSettings.maxRadius || Math.sqrt(width * width + height * height) / 2
564
+
565
+ return { cx, cy, innerRadius, maxRadius, outerRadius }
566
+ }
567
+
568
+ const parseDeltaAngle = (startAngle: number, endAngle: number) => {
569
+ const sign = mathSign(endAngle - startAngle)
570
+ const deltaAngle = Math.min(Math.abs(endAngle - startAngle), 360)
571
+
572
+ return sign * deltaAngle
573
+ }
574
+
575
+ function renderLabelLineItem(option: PieLabelLine, lineProps: CurveProps): JSX.Element {
576
+ if (typeof option === "function") {
577
+ return option(lineProps as Record<string, unknown>)
578
+ }
579
+
580
+ if (isJsxNode(option)) {
581
+ return <>{cloneJsxNodeWithProps(option, lineProps as unknown as Record<string, unknown>) as unknown as JSX.Element}</>
582
+ }
583
+
584
+ const className = clsx(
585
+ "recharts-pie-label-line",
586
+ typeof option !== "boolean"
587
+ ? String((option as unknown as Record<string, unknown>).className ?? "")
588
+ : "",
589
+ )
590
+ return <Curve {...lineProps} type="linear" class={className} />
591
+ }
592
+
593
+ function renderLabelItem(
594
+ option: PieLabel,
595
+ labelProps: PieLabelRenderProps,
596
+ value: unknown,
597
+ ): JSX.Element {
598
+ let label: unknown = value
599
+ if (typeof option === "function") {
600
+ label = option(labelProps)
601
+ /* if the function returned a JSX element, use it directly */
602
+ if (label != null && typeof label === "object") {
603
+ return label as JSX.Element
604
+ }
605
+ }
606
+
607
+ if (isJsxNode(option)) {
608
+ return <>{cloneJsxNodeWithProps(option, labelProps as unknown as Record<string, unknown>) as unknown as JSX.Element}</>
609
+ }
610
+
611
+ const className = clsx("recharts-pie-label-text", getClassNameFromUnknown(option))
612
+ const { style: labelStyle, ref: _labelRef, ...restLabelProps } = labelProps
613
+ return (
614
+ <Text
615
+ {...restLabelProps}
616
+ style={typeof labelStyle === "string" ? undefined : labelStyle}
617
+ textAnchor={labelProps.textAnchor as import("../component/Text").TextAnchor}
618
+ alignmentBaseline="middle"
619
+ className={className}
620
+ >
621
+ {label as string | number}
622
+ </Text>
623
+ )
624
+ }
625
+
626
+ /* eslint-disable solid/reactivity -- PieLabels reads are structural checks + map at setup; called from reactive JSX so props are stable per render */
627
+ function PieLabels(props: {
628
+ sectors: ReadonlyArray<PieSectorDataItem>
629
+ pieProps: WithoutId<InternalProps>
630
+ showLabels: boolean
631
+ }): JSX.Element {
632
+ return (
633
+ <Show when={!!props.showLabels && !!props.pieProps.label && props.sectors != null}>
634
+ <PieLabelsBody pieProps={props.pieProps} sectors={props.sectors} />
635
+ </Show>
636
+ )
637
+ }
638
+
639
+ function PieLabelsBody(props: {
640
+ sectors: ReadonlyArray<PieSectorDataItem>
641
+ pieProps: WithoutId<InternalProps>
642
+ }): JSX.Element {
643
+ const pieProps = createMemo(() => svgPropertiesNoEvents(props.pieProps))
644
+ const customLabelProps = createMemo(() =>
645
+ svgPropertiesNoEventsFromUnknown(props.pieProps.label),
646
+ )
647
+ const customLabelLineProps = createMemo(() =>
648
+ svgPropertiesNoEventsFromUnknown(props.pieProps.labelLine),
649
+ )
650
+ const offsetRadius = createMemo(() => {
651
+ const label = props.pieProps.label
652
+ if (
653
+ typeof label === "object" &&
654
+ label != null &&
655
+ "offsetRadius" in label &&
656
+ typeof label.offsetRadius === "number"
657
+ ) {
658
+ return label.offsetRadius
659
+ }
660
+ return 20
661
+ })
662
+
663
+ return (
664
+ <Layer class="recharts-pie-labels">
665
+ <For each={props.sectors}>
666
+ {(entry: PieSectorDataItem, iAccessor) => {
667
+ const i = untrack(() => iAccessor())
668
+ const node = createMemo(() => {
669
+ const midAngle = (entry.startAngle + entry.endAngle) / 2
670
+ const endPoint = polarToCartesian(
671
+ entry.cx,
672
+ entry.cy,
673
+ entry.outerRadius + offsetRadius(),
674
+ midAngle,
675
+ )
676
+ const labelItemProps: PieLabelRenderProps = {
677
+ ...pieProps(),
678
+ ...entry,
679
+ stroke: "none",
680
+ ...customLabelProps(),
681
+ index: i,
682
+ textAnchor: getTextAnchor(endPoint.x, entry.cx),
683
+ ...endPoint,
684
+ } as PieLabelRenderProps
685
+ const lineProps: CurveProps = {
686
+ ...pieProps(),
687
+ ...entry,
688
+ fill: "none",
689
+ stroke: entry.fill,
690
+ ...customLabelLineProps(),
691
+ index: i,
692
+ points: [
693
+ polarToCartesian(entry.cx, entry.cy, entry.outerRadius, midAngle),
694
+ endPoint,
695
+ ],
696
+ } as CurveProps
697
+
698
+ return (
699
+ <ZIndexLayer zIndex={DefaultZIndexes.label}>
700
+ <Layer>
701
+ <Show when={props.pieProps.labelLine}>
702
+ {renderLabelLineItem(props.pieProps.labelLine as PieLabelLine, lineProps)}
703
+ </Show>
704
+ {renderLabelItem(
705
+ props.pieProps.label as PieLabel,
706
+ labelItemProps,
707
+ getValueByDataKey(
708
+ entry,
709
+ props.pieProps.dataKey as DataKey<PieSectorDataItem>,
710
+ ),
711
+ )}
712
+ </Layer>
713
+ </ZIndexLayer>
714
+ )
715
+ })
716
+ return node as unknown as JSX.Element
717
+ }}
718
+ </For>
719
+ </Layer>
720
+ )
721
+ }
722
+ /* eslint-enable solid/reactivity */
723
+
724
+ /* eslint-disable solid/reactivity -- PieLabelList reads are structural type checks at setup; called from reactive JSX, stable per render */
725
+ function PieLabelList(props: {
726
+ sectors: ReadonlyArray<PieSectorDataItem>
727
+ pieProps: WithoutId<InternalProps>
728
+ showLabels: boolean
729
+ }): JSX.Element {
730
+ if (
731
+ typeof props.pieProps.label === "object" &&
732
+ props.pieProps.label != null &&
733
+ "position" in props.pieProps.label
734
+ ) {
735
+ return <LabelListFromLabelProp label={props.pieProps.label} />
736
+ }
737
+ return (
738
+ <PieLabels sectors={props.sectors} pieProps={props.pieProps} showLabels={props.showLabels} />
739
+ )
740
+ }
741
+ /* eslint-enable solid/reactivity */
742
+
743
+ function PieSectors(props: PieSectorsProps): JSX.Element {
744
+ const ctx = useChartStore()
745
+ /* GOTCHA-016-C: one entry per pointer move across both event pairs, shared by all sectors. */
746
+ const hover = createHoverDedupe()
747
+ const activeIndex = createMemo(() =>
748
+ ctx ? selectActiveTooltipIndex(ctx.store) : undefined,
749
+ )
750
+ const activeDataKey = createMemo(() =>
751
+ ctx ? selectActiveTooltipDataKey(ctx.store) : undefined,
752
+ )
753
+ const activeGraphicalItemId = createMemo(() =>
754
+ ctx ? selectActiveTooltipGraphicalItemId(ctx.store) : undefined,
755
+ )
756
+
757
+ /* eslint-disable solid/reactivity -- id is a stable identifier; handler and dataKey sources are accessors read at event time; sectors null check is structural */
758
+ /* GOTCHA-005-D: pass live accessors — dot-access at hook setup snapshots the value. */
759
+ const onMouseEnterFromContext = useMouseEnterItemDispatch(
760
+ () => props.allOtherPieProps.onMouseEnter as never,
761
+ () => props.allOtherPieProps.dataKey,
762
+ props.id,
763
+ )
764
+ const onMouseLeaveFromContext = useMouseLeaveItemDispatch(
765
+ () => props.allOtherPieProps.onMouseLeave as never,
766
+ )
767
+ const onClickFromContext = useMouseClickItemDispatch(
768
+ () => props.allOtherPieProps.onClick as never,
769
+ () => props.allOtherPieProps.dataKey,
770
+ props.id,
771
+ )
772
+ /* Once per series, not per sector: the rest-spread copies every Pie prop. */
773
+ const restOfAllOtherProps = createMemo((): Record<string, unknown> => {
774
+ const { onMouseEnter, onClick, onMouseLeave, ...rest } =
775
+ props.allOtherPieProps as unknown as Record<string, unknown>
776
+ void onMouseEnter
777
+ void onClick
778
+ void onMouseLeave
779
+ return rest
780
+ })
781
+
782
+ /* eslint-enable solid/reactivity */
783
+
784
+ return (
785
+ <Show when={props.sectors != null && props.sectors.length > 0}>
786
+ <For each={props.sectors}>
787
+ {(entry: PieSectorDataItem, iAccessor) => {
788
+ /* eslint-disable-next-line solid/reactivity -- iAccessor() snapshotted intentionally; i is used as a static index, not a reactive signal, per GOTCHA-014-H */
789
+ const i = untrack(() => iAccessor())
790
+ /* GOTCHA-014-H: per-sector reactive snapshots live INSIDE For's child fn so
791
+ activeIndex/activeDataKey changes do NOT re-run the outer JSX expression
792
+ that holds the For. Solid's plain `arr.map` inside JSX wraps the whole
793
+ map in one memo — any reactive read in the body re-creates every DOM
794
+ node, dropping `$$click` event delegation bindings between the
795
+ pointermove/pointerdown of `userEvent.click`. */
796
+ const isHidden = createMemo(
797
+ () =>
798
+ entry?.startAngle === 0 &&
799
+ entry?.endAngle === 0 &&
800
+ props.sectors.length !== 1,
801
+ )
802
+ const graphicalItemMatches = createMemo(
803
+ () => activeGraphicalItemId() == null || activeGraphicalItemId() === props.id,
804
+ )
805
+ const isActive = createMemo(
806
+ () =>
807
+ String(i) === activeIndex() &&
808
+ (activeDataKey() == null || props.allOtherPieProps.dataKey === activeDataKey()) &&
809
+ graphicalItemMatches(),
810
+ )
811
+ /* Not memoized: an element option must be evaluated where Shape reads it, inside
812
+ its ShapeElementPropsProvider (each read of an element prop mints a new shape). */
813
+ const sectorOptions = () => {
814
+ if (isActive()) {
815
+ const activeShape = props.activeShape
816
+ if (activeShape) {
817
+ return activeShape
818
+ }
819
+ }
820
+ return activeIndex() ? props.inactiveShape : null
821
+ }
822
+ const sectorProps = {
823
+ ...entry,
824
+ /* Getters: the spread into <Shape> reads these inside its tracked props. */
825
+ get animationElapsedTime() {
826
+ return props.animationElapsedTime
827
+ },
828
+ get isAnimating() {
829
+ return props.isAnimating
830
+ },
831
+ get isEntrance() {
832
+ return props.isEntrance
833
+ },
834
+ stroke: entry.stroke,
835
+ tabindex: -1,
836
+ [DATA_ITEM_INDEX_ATTRIBUTE_NAME]: i,
837
+ [DATA_ITEM_GRAPHICAL_ITEM_ID_ATTRIBUTE_NAME]: props.id,
838
+ }
839
+
840
+ /* GOTCHA-016-C: React's synthetic onMouseEnter/Leave fired on native mouseover/mouseout. Solid binds 1:1 — bind both pairs so fireEvent.mouseEnter, fireEvent.mouseOver, and user.hover all dispatch; dedupe via per-instance entry flag. Compose adapted user onMouseOver/Out handlers ahead of context dispatch. */
841
+ const adapted = (adaptEventsOfChild(untrack(() => restOfAllOtherProps()), entry, i) ?? {}) as Record<
842
+ string,
843
+ ((e: Event) => void) | undefined
844
+ >
845
+ const enterHandler = onMouseEnterFromContext(entry, i)
846
+ const leaveHandler = onMouseLeaveFromContext(entry, i)
847
+ const userOver = adapted.onMouseOver
848
+ const userOut = adapted.onMouseOut
849
+ const fireEnter = (e: MouseEvent & { currentTarget: SVGElement }) => {
850
+ if (!hover.enter(e)) return
851
+ userOver?.(e)
852
+ enterHandler(e)
853
+ }
854
+ const fireLeave = (e: MouseEvent & { currentTarget: SVGElement }) => {
855
+ if (!hover.leave(e)) return
856
+ userOut?.(e)
857
+ leaveHandler(e)
858
+ }
859
+ const clickHandler = onClickFromContext(entry, i)
860
+ return (
861
+ <Show when={!isHidden()}>
862
+ <Layer
863
+ tabindex={-1}
864
+ class="recharts-pie-sector"
865
+ {...adapted}
866
+ onMouseEnter={fireEnter}
867
+ onMouseOver={fireEnter}
868
+ onMouseLeave={fireLeave}
869
+ onMouseOut={fireLeave}
870
+ onClick={clickHandler}
871
+ >
872
+ <Shape
873
+ option={props.shape ?? sectorOptions()}
874
+ index={i}
875
+ shapeType="sector"
876
+ isActive={isActive()}
877
+ {...sectorProps}
878
+ />
879
+ </Layer>
880
+ </Show>
881
+ )
882
+ }}
883
+ </For>
884
+ </Show>
885
+ )
886
+ }
887
+
888
+ export function computePieSectors({
889
+ pieSettings,
890
+ displayedData,
891
+ cells,
892
+ offset,
893
+ }: {
894
+ pieSettings: PieSettings
895
+ displayedData: ChartData
896
+ cells: ReadonlyArray<JSX.Element> | undefined
897
+ offset: ChartOffsetInternal
898
+ }): ReadonlyArray<PieSectorDataItem> | undefined {
899
+ const { cornerRadius, startAngle, endAngle, dataKey, nameKey, tooltipType } = pieSettings
900
+ const minAngle = Math.abs(pieSettings.minAngle)
901
+ const deltaAngle = parseDeltaAngle(startAngle, endAngle)
902
+ const absDeltaAngle = Math.abs(deltaAngle)
903
+ const paddingAngle = displayedData.length <= 1 ? 0 : (pieSettings.paddingAngle ?? 0)
904
+
905
+ const notZeroItemCount = displayedData.filter(
906
+ (entry) => getValueByDataKey(entry, dataKey, 0) !== 0,
907
+ ).length
908
+ const totalPaddingAngle =
909
+ (absDeltaAngle >= 360 ? notZeroItemCount : notZeroItemCount - 1) * paddingAngle
910
+
911
+ const sum = displayedData.reduce((result: number, entry: unknown) => {
912
+ const val = getValueByDataKey(entry, dataKey, 0)
913
+ return result + (isNumber(val) ? val : 0)
914
+ }, 0)
915
+
916
+ /*
917
+ * Only apply minAngle redistribution when at least one non-zero segment's
918
+ * natural angle falls below the minAngle threshold. Otherwise, minAngle
919
+ * unnecessarily shifts all segments even when none need the boost.
920
+ * See: https://github.com/recharts/recharts/issues/6814
921
+ */
922
+ const needsMinAngleAdjustment =
923
+ minAngle > 0 &&
924
+ sum > 0 &&
925
+ displayedData.some((entry) => {
926
+ const val = getValueByDataKey(entry, dataKey, 0)
927
+ const percent = (isNumber(val) ? val : 0) / sum
928
+ return val !== 0 && percent * absDeltaAngle < minAngle
929
+ })
930
+ const effectiveMinAngle = needsMinAngleAdjustment ? minAngle : 0
931
+
932
+ const realTotalAngle = absDeltaAngle - notZeroItemCount * effectiveMinAngle - totalPaddingAngle
933
+ let sectors: PieSectorDataItem[] | undefined
934
+
935
+ if (sum > 0) {
936
+ let prev: PieSectorDataItem
937
+ sectors = displayedData.map((entry: unknown, i: number) => {
938
+ const val: number = getValueByDataKey(entry, dataKey, 0)
939
+ const name: string = getValueByDataKey(entry, nameKey, i)
940
+ const coordinate: PieCoordinate = parseCoordinateOfPie(pieSettings, offset, entry)
941
+ const percent = (isNumber(val) ? val : 0) / sum
942
+ let tempStartAngle: number
943
+
944
+ const entryWithCellInfo: RealPieData = {
945
+ ...(entry as Record<string, unknown>),
946
+ ...(cells && cells[i] && (cells[i] as unknown as { props: Record<string, unknown> }).props),
947
+ }
948
+ const sectorColor =
949
+ entryWithCellInfo != null && "fill" in entryWithCellInfo && typeof entryWithCellInfo.fill === "string"
950
+ ? entryWithCellInfo.fill
951
+ : pieSettings.fill
952
+
953
+ if (i) {
954
+ tempStartAngle = prev.endAngle + mathSign(deltaAngle) * paddingAngle * (val !== 0 ? 1 : 0)
955
+ } else {
956
+ tempStartAngle = startAngle
957
+ }
958
+
959
+ const tempEndAngle =
960
+ tempStartAngle +
961
+ mathSign(deltaAngle) * ((val !== 0 ? effectiveMinAngle : 0) + percent * realTotalAngle)
962
+ const midAngle = (tempStartAngle + tempEndAngle) / 2
963
+ const middleRadius = (coordinate.innerRadius + coordinate.outerRadius) / 2
964
+
965
+ const tooltipPayload: TooltipPayload = [
966
+ {
967
+ color: sectorColor,
968
+ dataKey,
969
+ fill: sectorColor,
970
+ graphicalItemId: pieSettings.id,
971
+ name,
972
+ payload: entryWithCellInfo,
973
+ type: tooltipType,
974
+ value: val,
975
+ },
976
+ ]
977
+ const tooltipPosition = polarToCartesian(coordinate.cx, coordinate.cy, middleRadius, midAngle)
978
+
979
+ prev = {
980
+ ...pieSettings.presentationProps,
981
+ percent,
982
+ cornerRadius: typeof cornerRadius === "string" ? parseFloat(cornerRadius) : cornerRadius,
983
+ name,
984
+ tooltipPayload,
985
+ midAngle,
986
+ middleRadius,
987
+ tooltipPosition,
988
+ ...entryWithCellInfo,
989
+ ...coordinate,
990
+ value: val,
991
+ dataKey,
992
+ startAngle: tempStartAngle,
993
+ endAngle: tempEndAngle,
994
+ payload: entryWithCellInfo,
995
+ paddingAngle: val !== 0 ? mathSign(deltaAngle) * paddingAngle : 0,
996
+ } as PieSectorDataItem
997
+ return prev
998
+ })
999
+ }
1000
+ return sectors
1001
+ }
1002
+
1003
+ function PieLabelListProvider(props: {
1004
+ showLabels: boolean
1005
+ sectors: ReadonlyArray<PieSectorDataItem>
1006
+ children: JSX.Element
1007
+ }): JSX.Element {
1008
+ const labelListEntries = createMemo((): ReadonlyArray<PolarLabelListEntry> => {
1009
+ if (!props.showLabels || !props.sectors) {
1010
+ return []
1011
+ }
1012
+ return props.sectors.map(
1013
+ (entry): PolarLabelListEntry => ({
1014
+ clockWise: false,
1015
+ fill: entry.fill,
1016
+ parentViewBox: undefined,
1017
+ payload: entry.payload,
1018
+ value: entry.value,
1019
+ viewBox: {
1020
+ clockWise: false,
1021
+ cx: entry.cx,
1022
+ cy: entry.cy,
1023
+ endAngle: entry.endAngle,
1024
+ innerRadius: entry.innerRadius,
1025
+ outerRadius: entry.outerRadius,
1026
+ startAngle: entry.startAngle,
1027
+ },
1028
+ }),
1029
+ )
1030
+ })
1031
+ /* eslint-disable solid/reactivity -- Provider value reads labelListEntries() and props.showLabels inside JSX attribute; both are reactive */
1032
+ return (
1033
+ <PolarLabelListContextProvider value={props.showLabels ? labelListEntries() : undefined}>
1034
+ {props.children}
1035
+ </PolarLabelListContextProvider>
1036
+ )
1037
+ /* eslint-enable solid/reactivity */
1038
+ }
1039
+
1040
+ type WithoutId<T> = Omit<T, "id">
1041
+
1042
+ const defaultPieAnimateItems: AnimationInterpolateFn<PieSectorDataItem, PolarLayout> = (
1043
+ items,
1044
+ animationElapsedTime,
1045
+ ) => {
1046
+ if (items == null) return []
1047
+ const stepData: PieSectorDataItem[] = []
1048
+ const firstNonRemoved = items.find((item) => item.status !== "removed")
1049
+ let curAngle: number = firstNonRemoved ? firstNonRemoved.next.startAngle : 0
1050
+
1051
+ items.forEach((item, index) => {
1052
+ if (item.status === "removed") return
1053
+ const paddingAngle = index > 0 ? get(item.next, "paddingAngle", 0) : 0
1054
+
1055
+ if (item.status === "matched") {
1056
+ const angle = interpolate(
1057
+ item.prev.endAngle - item.prev.startAngle,
1058
+ item.next.endAngle - item.next.startAngle,
1059
+ animationElapsedTime,
1060
+ )
1061
+ const latest = {
1062
+ ...item.next,
1063
+ endAngle: curAngle + angle + paddingAngle,
1064
+ startAngle: curAngle + paddingAngle,
1065
+ }
1066
+ stepData.push(latest)
1067
+ curAngle = latest.endAngle
1068
+ } else {
1069
+ // added
1070
+ const deltaAngle = interpolate(0, item.next.endAngle - item.next.startAngle, animationElapsedTime)
1071
+ const latest = {
1072
+ ...item.next,
1073
+ endAngle: curAngle + deltaAngle + paddingAngle,
1074
+ startAngle: curAngle + paddingAngle,
1075
+ }
1076
+ stepData.push(latest)
1077
+ curAngle = latest.endAngle
1078
+ }
1079
+ })
1080
+ return stepData
1081
+ }
1082
+
1083
+ function SectorsWithAnimation(props: {
1084
+ pieProps: WithoutId<InternalProps>
1085
+ id: GraphicalItemId
1086
+ previousSectorsRef: { current: ReadonlyArray<PieSectorDataItem> | null }
1087
+ }): JSX.Element {
1088
+ const { isAnimating, handleAnimationStart, handleAnimationEnd } = useAnimationCallbacks(
1089
+ () => props.pieProps.onAnimationStart,
1090
+ () => props.pieProps.onAnimationEnd,
1091
+ )
1092
+ const layout = createMemo(() => usePolarChartLayout())
1093
+
1094
+ return (
1095
+ <Show when={layout()}>
1096
+ {(polarLayout) => (
1097
+ <PieLabelListProvider showLabels={!isAnimating()} sectors={props.pieProps.sectors}>
1098
+ <AnimatedItems
1099
+ animationInput={props.pieProps.sectors}
1100
+ animationIdPrefix="recharts-pie-"
1101
+ items={props.pieProps.sectors}
1102
+ previousItemsRef={props.previousSectorsRef}
1103
+ isAnimationActive={props.pieProps.isAnimationActive}
1104
+ animationBegin={props.pieProps.animationBegin}
1105
+ animationDuration={props.pieProps.animationDuration}
1106
+ animationEasing={props.pieProps.animationEasing}
1107
+ onAnimationStart={handleAnimationStart}
1108
+ onAnimationEnd={handleAnimationEnd}
1109
+ animationInterpolateFn={props.pieProps.animationInterpolateFn}
1110
+ animationMatchBy={props.pieProps.animationMatchBy}
1111
+ layout={polarLayout()}
1112
+ >
1113
+ {(stepData, animationElapsedTime, isEntrance) => (
1114
+ <Layer>
1115
+ <PieSectors
1116
+ sectors={stepData()}
1117
+ activeShape={props.pieProps.activeShape}
1118
+ inactiveShape={props.pieProps.inactiveShape}
1119
+ allOtherPieProps={props.pieProps}
1120
+ shape={props.pieProps.shape}
1121
+ id={props.id}
1122
+ animationElapsedTime={animationElapsedTime()}
1123
+ isAnimating={isAnimating() || animationElapsedTime() < 1}
1124
+ isEntrance={isEntrance()}
1125
+ />
1126
+ </Layer>
1127
+ )}
1128
+ </AnimatedItems>
1129
+ <PieLabelList
1130
+ showLabels={!isAnimating()}
1131
+ sectors={props.pieProps.sectors}
1132
+ pieProps={props.pieProps}
1133
+ />
1134
+ </PieLabelListProvider>
1135
+ )}
1136
+ </Show>
1137
+ )
1138
+ }
1139
+
1140
+ function RenderSectors(props: {
1141
+ pieProps: WithoutId<InternalProps>
1142
+ id: GraphicalItemId
1143
+ }): JSX.Element {
1144
+ const previousSectorsRef: { current: ReadonlyArray<PieSectorDataItem> | null } = {
1145
+ current: null,
1146
+ }
1147
+ return (
1148
+ <SectorsWithAnimation
1149
+ pieProps={props.pieProps}
1150
+ id={props.id}
1151
+ previousSectorsRef={previousSectorsRef}
1152
+ />
1153
+ )
1154
+ }
1155
+
1156
+ export const defaultPieProps = {
1157
+ animationBegin: 400,
1158
+ animationDuration: 1500,
1159
+ animationEasing: "ease",
1160
+ animationInterpolateFn: defaultPieAnimateItems,
1161
+ animationMatchBy: matchAppend,
1162
+ cx: "50%",
1163
+ cy: "50%",
1164
+ dataKey: "value",
1165
+ endAngle: 360,
1166
+ fill: "#808080",
1167
+ hide: false,
1168
+ innerRadius: 0,
1169
+ isAnimationActive: "auto",
1170
+ label: false,
1171
+ labelLine: true,
1172
+ legendType: "rect",
1173
+ minAngle: 0,
1174
+ nameKey: "name",
1175
+ outerRadius: "80%",
1176
+ paddingAngle: 0,
1177
+ rootTabIndex: 0,
1178
+ startAngle: 0,
1179
+ stroke: "#fff",
1180
+ zIndex: DefaultZIndexes.area,
1181
+ } as const satisfies Partial<Props>
1182
+
1183
+ function PieChildrenScope(props: { childrenProps: { children?: JSX.Element } }): JSX.Element {
1184
+ /* GOTCHA-017: memoize children INSIDE PolarLabelContext + CellsContext so
1185
+ Label/Cell createComponent runs with those providers as owner. Reading
1186
+ `children` as a JSX child of PieImpl mints Label outside polar context. */
1187
+ const memoizedChildren = createMemo(() => props.childrenProps.children)
1188
+ return <>{memoizedChildren()}</>
1189
+ }
1190
+
1191
+ function PieImpl(
1192
+ props: Omit<InternalProps, "sectors"> & { childrenProps: { children?: JSX.Element } },
1193
+ ): JSX.Element {
1194
+ /* keep `props` reactive end-to-end. destructuring/spreading freezes the Solid
1195
+ props proxy at this scope and downstream sectors/animation lose live updates. */
1196
+ const [idProps, rest] = splitProps(props, ["id"])
1197
+ const [childrenBag, propsWithoutId] = splitProps(rest, ["childrenProps"])
1198
+ const id = (): GraphicalItemId => idProps.id
1199
+ const ctx = useChartStore()
1200
+ const stateCtx = useContext(RechartsStateContext)
1201
+
1202
+ /* GOTCHA-013/017: Cell children register into this registry from inside the
1203
+ Provider scope; cells() returns insertion-ordered { props } records that
1204
+ selectPieSectors merges into per-sector data (fill/stroke/etc). */
1205
+ const cellsRegistry = createCellsRegistry()
1206
+ /* perf: memo so downstream selectors don't re-derive on every registry signal write
1207
+ that doesn't change the resolved array reference (e.g. no-op Cell re-renders). */
1208
+ const cells = createMemo((): ReadonlyArray<Record<string, unknown>> | undefined => {
1209
+ const list = cellsRegistry.cells()
1210
+ return list.length === 0 ? undefined : (list as unknown as ReadonlyArray<Record<string, unknown>>)
1211
+ })
1212
+
1213
+ const sectors = createMemo(() => {
1214
+ /* When new chartState has a settings entry, pass it as override so mutations
1215
+ to graphicalItems[id].settings (fine-grained Solid store) invalidate this
1216
+ memo and drive re-derivation without touching the legacy store. */
1217
+ const solidEntry = stateCtx?.state.graphicalItems[id()]
1218
+ const pieOverride =
1219
+ solidEntry != null && solidEntry.type === "pie"
1220
+ ? (solidEntry.settings as PieSettings)
1221
+ : undefined
1222
+ return ctx ? selectPieSectors(ctx.store, id(), cells(), pieOverride) : undefined
1223
+ })
1224
+
1225
+ const layerClass = (): string => clsx("recharts-pie", props.className)
1226
+ const firstSector = createMemo(() => sectors()?.[0])
1227
+
1228
+ return (
1229
+ <LabelListContextBridge>
1230
+ {/* Children always mount so <Cell/>s register even before any sector exists (they
1231
+ can be the only data source); polar labels wait until the first sector. */}
1232
+ <PolarLabelContextProvider
1233
+ pending={firstSector() == null}
1234
+ cx={firstSector()?.cx ?? 0}
1235
+ cy={firstSector()?.cy ?? 0}
1236
+ innerRadius={firstSector()?.innerRadius ?? 0}
1237
+ outerRadius={firstSector()?.outerRadius ?? 0}
1238
+ startAngle={props.startAngle ?? 0}
1239
+ endAngle={props.endAngle ?? 0}
1240
+ clockWise={false}
1241
+ >
1242
+ <CellsContextProvider value={cellsRegistry}>
1243
+ <PieChildrenScope childrenProps={childrenBag.childrenProps} />
1244
+ </CellsContextProvider>
1245
+ </PolarLabelContextProvider>
1246
+ <Show
1247
+ when={!props.hide && sectors() != null}
1248
+ fallback={<Layer tabindex={props.rootTabIndex} class={layerClass()} />}
1249
+ >
1250
+ {(() => {
1251
+ const sx = (): Readonly<PieSectorDataItem[]> => sectors() ?? []
1252
+ const renderProps = mergeProps(propsWithoutId, {
1253
+ get sectors() {
1254
+ return sx()
1255
+ },
1256
+ }) as WithoutId<InternalProps>
1257
+ return (
1258
+ <ZIndexLayer zIndex={props.zIndex}>
1259
+ <SetPieTooltipEntrySettings
1260
+ activeShape={props.activeShape}
1261
+ dataKey={props.dataKey}
1262
+ nameKey={props.nameKey}
1263
+ sectors={sx()}
1264
+ stroke={props.stroke}
1265
+ strokeWidth={props.strokeWidth}
1266
+ fill={props.fill}
1267
+ name={props.name}
1268
+ hide={props.hide}
1269
+ tooltipType={props.tooltipType}
1270
+ formatter={props.formatter}
1271
+ id={id()}
1272
+ />
1273
+ <Layer tabindex={props.rootTabIndex} class={layerClass()}>
1274
+ <RenderSectors pieProps={renderProps} id={id()} />
1275
+ </Layer>
1276
+ </ZIndexLayer>
1277
+ )
1278
+ })()}
1279
+ </Show>
1280
+ </LabelListContextBridge>
1281
+ )
1282
+ }
1283
+
1284
+ type PropsWithResolvedDefaults = RequiresDefaultProps<Props, typeof defaultPieProps>
1285
+
1286
+ /**
1287
+ * @consumes PolarChartContext
1288
+ * @provides LabelListContext
1289
+ * @provides CellReader
1290
+ */
1291
+ function PieFn(outsideProps: Props): JSX.Element {
1292
+ /* GOTCHA-013: split children before resolveDefaultProps. The destructure
1293
+ `{ id, ...propsWithoutId } = resolveDefaultProps(...)` and the subsequent
1294
+ `{...propsWithoutId}` spreads enumerate the props proxy and read `children`
1295
+ eagerly — Cell/etc. children invoke before RegisterGraphicalItemId installs
1296
+ its Provider. */
1297
+ const [childrenProps, restProps] = splitProps(outsideProps, ["children"])
1298
+ const props: PropsWithResolvedDefaults = resolveDefaultProps(restProps, defaultPieProps)
1299
+ const [idProps, propsWithoutId] = splitProps(props, ["id"])
1300
+ const presentationProps = createMemo(
1301
+ (): PiePresentationProps | null => svgPropertiesNoEvents(propsWithoutId),
1302
+ )
1303
+
1304
+ return (
1305
+ <RegisterGraphicalItemId id={idProps.id} type="pie">
1306
+ {(id: GraphicalItemId) => {
1307
+ /* GOTCHA-017: do NOT evaluate childrenProps.children here — Cell
1308
+ createComponent calls would fire BEFORE PieImpl mounts its
1309
+ cellsRegistry Provider. Pass `childrenProps` reference; PieImpl
1310
+ memoizes inside its own Provider scope. */
1311
+ return (
1312
+ <>
1313
+ <SetPolarGraphicalItem
1314
+ type="pie"
1315
+ id={id}
1316
+ data={propsWithoutId.data}
1317
+ dataKey={propsWithoutId.dataKey}
1318
+ hide={propsWithoutId.hide}
1319
+ angleAxisId={0}
1320
+ radiusAxisId={0}
1321
+ name={propsWithoutId.name}
1322
+ nameKey={propsWithoutId.nameKey}
1323
+ tooltipType={propsWithoutId.tooltipType}
1324
+ legendType={propsWithoutId.legendType}
1325
+ fill={propsWithoutId.fill}
1326
+ cx={propsWithoutId.cx}
1327
+ cy={propsWithoutId.cy}
1328
+ startAngle={propsWithoutId.startAngle}
1329
+ endAngle={propsWithoutId.endAngle}
1330
+ paddingAngle={propsWithoutId.paddingAngle}
1331
+ minAngle={propsWithoutId.minAngle}
1332
+ innerRadius={propsWithoutId.innerRadius}
1333
+ outerRadius={propsWithoutId.outerRadius}
1334
+ cornerRadius={propsWithoutId.cornerRadius}
1335
+ presentationProps={presentationProps()}
1336
+ maxRadius={props.maxRadius}
1337
+ />
1338
+ <SetPiePayloadLegend {...propsWithoutId} id={id} />
1339
+ <PieImpl
1340
+ {...(propsWithoutId as Omit<InternalProps, "sectors" | "id">)}
1341
+ id={id}
1342
+ childrenProps={childrenProps}
1343
+ />
1344
+ </>
1345
+ )
1346
+ }}
1347
+ </RegisterGraphicalItemId>
1348
+ )
1349
+ }
1350
+
1351
+ /**
1352
+ * Typed entry point: the generics constrain props at the call site, like upstream.
1353
+ */
1354
+ /* eslint-disable-next-line typescript-eslint/no-explicit-any -- upstream contract: untyped usage accepts any data */
1355
+ export const Pie = PieFn as {
1356
+ <DataPointType = any, DataValueType = any>(props: Props<DataPointType, DataValueType>): JSX.Element
1357
+ /* eslint-disable-next-line typescript-eslint/no-explicit-any -- upstream fallback overload for mismatched data/dataKey */
1358
+ (props: Props<any, any>): JSX.Element
1359
+ displayName?: string
1360
+ }