@coinbase/cds-mobile-visualization 3.3.0 → 3.4.0-beta.10

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 (265) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/dts/chart/CartesianChart.d.ts +125 -0
  3. package/dts/chart/CartesianChart.d.ts.map +1 -0
  4. package/dts/chart/ChartContextBridge.d.ts +28 -0
  5. package/dts/chart/ChartContextBridge.d.ts.map +1 -0
  6. package/dts/chart/ChartProvider.d.ts +6 -0
  7. package/dts/chart/ChartProvider.d.ts.map +1 -0
  8. package/dts/chart/Path.d.ts +91 -0
  9. package/dts/chart/Path.d.ts.map +1 -0
  10. package/dts/chart/PeriodSelector.d.ts +85 -0
  11. package/dts/chart/PeriodSelector.d.ts.map +1 -0
  12. package/dts/chart/area/Area.d.ts +77 -0
  13. package/dts/chart/area/Area.d.ts.map +1 -0
  14. package/dts/chart/area/AreaChart.d.ts +131 -0
  15. package/dts/chart/area/AreaChart.d.ts.map +1 -0
  16. package/dts/chart/area/DottedArea.d.ts +46 -0
  17. package/dts/chart/area/DottedArea.d.ts.map +1 -0
  18. package/dts/chart/area/GradientArea.d.ts +36 -0
  19. package/dts/chart/area/GradientArea.d.ts.map +1 -0
  20. package/dts/chart/area/SolidArea.d.ts +23 -0
  21. package/dts/chart/area/SolidArea.d.ts.map +1 -0
  22. package/dts/chart/area/index.d.ts +6 -0
  23. package/dts/chart/area/index.d.ts.map +1 -0
  24. package/dts/chart/axis/Axis.d.ts +194 -0
  25. package/dts/chart/axis/Axis.d.ts.map +1 -0
  26. package/dts/chart/axis/DefaultAxisTickLabel.d.ts +8 -0
  27. package/dts/chart/axis/DefaultAxisTickLabel.d.ts.map +1 -0
  28. package/dts/chart/axis/XAxis.d.ts +16 -0
  29. package/dts/chart/axis/XAxis.d.ts.map +1 -0
  30. package/dts/chart/axis/YAxis.d.ts +21 -0
  31. package/dts/chart/axis/YAxis.d.ts.map +1 -0
  32. package/dts/chart/axis/index.d.ts +5 -0
  33. package/dts/chart/axis/index.d.ts.map +1 -0
  34. package/dts/chart/bar/Bar.d.ts +92 -0
  35. package/dts/chart/bar/Bar.d.ts.map +1 -0
  36. package/dts/chart/bar/BarChart.d.ts +113 -0
  37. package/dts/chart/bar/BarChart.d.ts.map +1 -0
  38. package/dts/chart/bar/BarPlot.d.ts +30 -0
  39. package/dts/chart/bar/BarPlot.d.ts.map +1 -0
  40. package/dts/chart/bar/BarStack.d.ts +102 -0
  41. package/dts/chart/bar/BarStack.d.ts.map +1 -0
  42. package/dts/chart/bar/BarStackGroup.d.ts +36 -0
  43. package/dts/chart/bar/BarStackGroup.d.ts.map +1 -0
  44. package/dts/chart/bar/DefaultBar.d.ts +7 -0
  45. package/dts/chart/bar/DefaultBar.d.ts.map +1 -0
  46. package/dts/chart/bar/DefaultBarStack.d.ts +7 -0
  47. package/dts/chart/bar/DefaultBarStack.d.ts.map +1 -0
  48. package/dts/chart/bar/index.d.ts +8 -0
  49. package/dts/chart/bar/index.d.ts.map +1 -0
  50. package/dts/chart/gradient/Gradient.d.ts +25 -0
  51. package/dts/chart/gradient/Gradient.d.ts.map +1 -0
  52. package/dts/chart/gradient/index.d.ts +2 -0
  53. package/dts/chart/gradient/index.d.ts.map +1 -0
  54. package/dts/chart/index.d.ts +15 -0
  55. package/dts/chart/index.d.ts.map +1 -0
  56. package/dts/chart/line/DefaultReferenceLineLabel.d.ts +9 -0
  57. package/dts/chart/line/DefaultReferenceLineLabel.d.ts.map +1 -0
  58. package/dts/chart/line/DottedLine.d.ts +20 -0
  59. package/dts/chart/line/DottedLine.d.ts.map +1 -0
  60. package/dts/chart/line/Line.d.ts +115 -0
  61. package/dts/chart/line/Line.d.ts.map +1 -0
  62. package/dts/chart/line/LineChart.d.ts +118 -0
  63. package/dts/chart/line/LineChart.d.ts.map +1 -0
  64. package/dts/chart/line/ReferenceLine.d.ts +139 -0
  65. package/dts/chart/line/ReferenceLine.d.ts.map +1 -0
  66. package/dts/chart/line/SolidLine.d.ts +15 -0
  67. package/dts/chart/line/SolidLine.d.ts.map +1 -0
  68. package/dts/chart/line/index.d.ts +7 -0
  69. package/dts/chart/line/index.d.ts.map +1 -0
  70. package/dts/chart/point/DefaultPointLabel.d.ts +10 -0
  71. package/dts/chart/point/DefaultPointLabel.d.ts.map +1 -0
  72. package/dts/chart/point/Point.d.ts +120 -0
  73. package/dts/chart/point/Point.d.ts.map +1 -0
  74. package/dts/chart/point/index.d.ts +3 -0
  75. package/dts/chart/point/index.d.ts.map +1 -0
  76. package/dts/chart/scrubber/DefaultScrubberBeacon.d.ts +8 -0
  77. package/dts/chart/scrubber/DefaultScrubberBeacon.d.ts.map +1 -0
  78. package/dts/chart/scrubber/DefaultScrubberBeaconLabel.d.ts +12 -0
  79. package/dts/chart/scrubber/DefaultScrubberBeaconLabel.d.ts.map +1 -0
  80. package/dts/chart/scrubber/DefaultScrubberLabel.d.ts +11 -0
  81. package/dts/chart/scrubber/DefaultScrubberLabel.d.ts.map +1 -0
  82. package/dts/chart/scrubber/Scrubber.d.ts +233 -0
  83. package/dts/chart/scrubber/Scrubber.d.ts.map +1 -0
  84. package/dts/chart/scrubber/ScrubberBeaconGroup.d.ts +44 -0
  85. package/dts/chart/scrubber/ScrubberBeaconGroup.d.ts.map +1 -0
  86. package/dts/chart/scrubber/ScrubberBeaconLabelGroup.d.ts +31 -0
  87. package/dts/chart/scrubber/ScrubberBeaconLabelGroup.d.ts.map +1 -0
  88. package/dts/chart/scrubber/ScrubberProvider.d.ts +20 -0
  89. package/dts/chart/scrubber/ScrubberProvider.d.ts.map +1 -0
  90. package/dts/chart/scrubber/index.d.ts +5 -0
  91. package/dts/chart/scrubber/index.d.ts.map +1 -0
  92. package/dts/chart/text/ChartText.d.ts +164 -0
  93. package/dts/chart/text/ChartText.d.ts.map +1 -0
  94. package/dts/chart/text/ChartTextGroup.d.ts +61 -0
  95. package/dts/chart/text/ChartTextGroup.d.ts.map +1 -0
  96. package/dts/chart/text/index.d.ts +3 -0
  97. package/dts/chart/text/index.d.ts.map +1 -0
  98. package/dts/chart/utils/axis.d.ts +342 -0
  99. package/dts/chart/utils/axis.d.ts.map +1 -0
  100. package/dts/chart/utils/bar.d.ts +20 -0
  101. package/dts/chart/utils/bar.d.ts.map +1 -0
  102. package/dts/chart/utils/chart.d.ts +124 -0
  103. package/dts/chart/utils/chart.d.ts.map +1 -0
  104. package/dts/chart/utils/context.d.ts +116 -0
  105. package/dts/chart/utils/context.d.ts.map +1 -0
  106. package/dts/chart/utils/gradient.d.ts +117 -0
  107. package/dts/chart/utils/gradient.d.ts.map +1 -0
  108. package/dts/chart/utils/index.d.ts +11 -0
  109. package/dts/chart/utils/index.d.ts.map +1 -0
  110. package/dts/chart/utils/path.d.ts +160 -0
  111. package/dts/chart/utils/path.d.ts.map +1 -0
  112. package/dts/chart/utils/point.d.ts +134 -0
  113. package/dts/chart/utils/point.d.ts.map +1 -0
  114. package/dts/chart/utils/scale.d.ts +134 -0
  115. package/dts/chart/utils/scale.d.ts.map +1 -0
  116. package/dts/chart/utils/scrubber.d.ts +39 -0
  117. package/dts/chart/utils/scrubber.d.ts.map +1 -0
  118. package/dts/chart/utils/transition.d.ts +140 -0
  119. package/dts/chart/utils/transition.d.ts.map +1 -0
  120. package/dts/index.d.ts +2 -1
  121. package/dts/index.d.ts.map +1 -1
  122. package/dts/sparkline/Counter.d.ts +7 -2
  123. package/dts/sparkline/Sparkline.d.ts +67 -16
  124. package/dts/sparkline/Sparkline.d.ts.map +1 -1
  125. package/dts/sparkline/SparklineArea.d.ts +10 -4
  126. package/dts/sparkline/SparklineArea.d.ts.map +1 -1
  127. package/dts/sparkline/SparklineAreaPattern.d.ts +12 -4
  128. package/dts/sparkline/SparklineAreaPattern.d.ts.map +1 -1
  129. package/dts/sparkline/SparklineGradient.d.ts +21 -10
  130. package/dts/sparkline/SparklineGradient.d.ts.map +1 -1
  131. package/dts/sparkline/__figma__/Sparkline.figma.d.ts +1 -1
  132. package/dts/sparkline/generateSparklineWithId.d.ts +8 -2
  133. package/dts/sparkline/generateSparklineWithId.d.ts.map +1 -1
  134. package/dts/sparkline/index.d.ts +1 -1
  135. package/dts/sparkline/sparkline-interactive/SparklineAccessibleView.d.ts +8 -3
  136. package/dts/sparkline/sparkline-interactive/SparklineInteractive.d.ts +132 -110
  137. package/dts/sparkline/sparkline-interactive/SparklineInteractive.d.ts.map +1 -1
  138. package/dts/sparkline/sparkline-interactive/SparklineInteractiveAnimatedPath.d.ts +22 -9
  139. package/dts/sparkline/sparkline-interactive/SparklineInteractiveAnimatedPath.d.ts.map +1 -1
  140. package/dts/sparkline/sparkline-interactive/SparklineInteractiveHoverDate.d.ts +18 -7
  141. package/dts/sparkline/sparkline-interactive/SparklineInteractiveLineVertical.d.ts +9 -4
  142. package/dts/sparkline/sparkline-interactive/SparklineInteractiveMarkerDates.d.ts +11 -6
  143. package/dts/sparkline/sparkline-interactive/SparklineInteractiveMinMax.d.ts +7 -5
  144. package/dts/sparkline/sparkline-interactive/SparklineInteractivePanGestureHandler.d.ts +22 -10
  145. package/dts/sparkline/sparkline-interactive/SparklineInteractivePaths.d.ts +21 -7
  146. package/dts/sparkline/sparkline-interactive/SparklineInteractivePaths.d.ts.map +1 -1
  147. package/dts/sparkline/sparkline-interactive/SparklineInteractivePeriodSelector.d.ts +21 -16
  148. package/dts/sparkline/sparkline-interactive/SparklineInteractiveProvider.d.ts +29 -23
  149. package/dts/sparkline/sparkline-interactive/SparklineInteractiveTimeseriesPaths.d.ts +22 -14
  150. package/dts/sparkline/sparkline-interactive/__figma__/SparklineInteractive.figma.d.ts +1 -1
  151. package/dts/sparkline/sparkline-interactive/useInterruptiblePathAnimation.d.ts +9 -5
  152. package/dts/sparkline/sparkline-interactive/useMinMaxTransform.d.ts +11 -6
  153. package/dts/sparkline/sparkline-interactive/useOpacityAnimation.d.ts +5 -2
  154. package/dts/sparkline/sparkline-interactive/useSparklineInteractiveConstants.d.ts +17 -17
  155. package/dts/sparkline/sparkline-interactive/useSparklineInteractiveLineStyles.d.ts +16 -13
  156. package/dts/sparkline/sparkline-interactive-header/SparklineInteractiveHeader.d.ts +106 -98
  157. package/dts/sparkline/sparkline-interactive-header/__figma__/SparklineInteractiveHeader.figma.d.ts +1 -1
  158. package/dts/sparkline/sparkline-interactive-header/useSparklineInteractiveHeaderStyles.d.ts +22 -19
  159. package/esm/chart/CartesianChart.js +335 -0
  160. package/esm/chart/ChartContextBridge.js +148 -0
  161. package/esm/chart/ChartProvider.js +10 -0
  162. package/esm/chart/Path.js +218 -0
  163. package/esm/chart/PeriodSelector.js +136 -0
  164. package/esm/chart/__stories__/CartesianChart.stories.js +723 -0
  165. package/esm/chart/__stories__/Chart.stories.js +77 -0
  166. package/esm/chart/__stories__/PeriodSelector.stories.js +322 -0
  167. package/esm/chart/area/Area.js +75 -0
  168. package/esm/chart/area/AreaChart.js +151 -0
  169. package/esm/chart/area/DottedArea.js +80 -0
  170. package/esm/chart/area/GradientArea.js +54 -0
  171. package/esm/chart/area/SolidArea.js +38 -0
  172. package/esm/chart/area/__stories__/AreaChart.stories.js +100 -0
  173. package/esm/chart/area/index.js +7 -0
  174. package/esm/chart/axis/Axis.js +45 -0
  175. package/esm/chart/axis/DefaultAxisTickLabel.js +11 -0
  176. package/esm/chart/axis/XAxis.js +188 -0
  177. package/esm/chart/axis/YAxis.js +177 -0
  178. package/esm/chart/axis/__stories__/Axis.stories.js +276 -0
  179. package/esm/chart/axis/index.js +6 -0
  180. package/esm/chart/bar/Bar.js +69 -0
  181. package/esm/chart/bar/BarChart.js +125 -0
  182. package/esm/chart/bar/BarPlot.js +102 -0
  183. package/esm/chart/bar/BarStack.js +551 -0
  184. package/esm/chart/bar/BarStackGroup.js +79 -0
  185. package/esm/chart/bar/DefaultBar.js +56 -0
  186. package/esm/chart/bar/DefaultBarStack.js +47 -0
  187. package/esm/chart/bar/__stories__/BarChart.stories.js +668 -0
  188. package/esm/chart/bar/index.js +9 -0
  189. package/esm/chart/gradient/Gradient.js +53 -0
  190. package/esm/chart/gradient/index.js +1 -0
  191. package/esm/chart/index.js +16 -0
  192. package/esm/chart/line/DefaultReferenceLineLabel.js +66 -0
  193. package/esm/chart/line/DottedLine.js +50 -0
  194. package/esm/chart/line/Line.js +178 -0
  195. package/esm/chart/line/LineChart.js +121 -0
  196. package/esm/chart/line/ReferenceLine.js +132 -0
  197. package/esm/chart/line/SolidLine.js +46 -0
  198. package/esm/chart/line/__stories__/LineChart.stories.js +2372 -0
  199. package/esm/chart/line/__stories__/ReferenceLine.stories.js +132 -0
  200. package/esm/chart/line/index.js +8 -0
  201. package/esm/chart/point/DefaultPointLabel.js +39 -0
  202. package/esm/chart/point/Point.js +188 -0
  203. package/esm/chart/point/index.js +2 -0
  204. package/esm/chart/scrubber/DefaultScrubberBeacon.js +179 -0
  205. package/esm/chart/scrubber/DefaultScrubberBeaconLabel.js +43 -0
  206. package/esm/chart/scrubber/DefaultScrubberLabel.js +28 -0
  207. package/esm/chart/scrubber/Scrubber.js +166 -0
  208. package/esm/chart/scrubber/ScrubberBeaconGroup.js +161 -0
  209. package/esm/chart/scrubber/ScrubberBeaconLabelGroup.js +185 -0
  210. package/esm/chart/scrubber/ScrubberProvider.js +135 -0
  211. package/esm/chart/scrubber/index.js +4 -0
  212. package/esm/chart/text/ChartText.js +305 -0
  213. package/esm/chart/text/ChartTextGroup.js +211 -0
  214. package/esm/chart/text/index.js +4 -0
  215. package/esm/chart/utils/axis.js +592 -0
  216. package/esm/chart/utils/bar.js +24 -0
  217. package/esm/chart/utils/chart.js +270 -0
  218. package/esm/chart/utils/context.js +15 -0
  219. package/esm/chart/utils/gradient.js +305 -0
  220. package/esm/chart/utils/index.js +12 -0
  221. package/esm/chart/utils/path.js +274 -0
  222. package/esm/chart/utils/point.js +229 -0
  223. package/esm/chart/utils/scale.js +277 -0
  224. package/esm/chart/utils/scrubber.js +139 -0
  225. package/esm/chart/utils/transition.js +185 -0
  226. package/esm/index.js +4 -1
  227. package/esm/sparkline/Sparkline.js +129 -16
  228. package/esm/sparkline/SparklineArea.js +7 -2
  229. package/esm/sparkline/SparklineAreaPattern.js +4 -2
  230. package/esm/sparkline/SparklineGradient.js +4 -0
  231. package/esm/sparkline/__stories__/Sparkline.stories.js +11 -7
  232. package/esm/sparkline/__stories__/SparklineGradient.stories.js +7 -4
  233. package/esm/sparkline/generateSparklineWithId.js +3 -2
  234. package/esm/sparkline/sparkline-interactive/SparklineInteractive.js +5 -1
  235. package/esm/sparkline/sparkline-interactive/SparklineInteractiveAnimatedPath.js +5 -2
  236. package/esm/sparkline/sparkline-interactive/SparklineInteractivePaths.js +4 -0
  237. package/esm/sparkline/sparkline-interactive/__stories__/SparklineInteractive.stories.js +76 -24
  238. package/esm/sparkline/sparkline-interactive-header/__stories__/SparklineInteractiveHeader.stories.js +17 -9
  239. package/package.json +17 -11
  240. package/dts/sparkline/__stories__/Sparkline.stories.d.ts +0 -3
  241. package/dts/sparkline/__stories__/Sparkline.stories.d.ts.map +0 -1
  242. package/dts/sparkline/__stories__/SparklineGradient.stories.d.ts +0 -3
  243. package/dts/sparkline/__stories__/SparklineGradient.stories.d.ts.map +0 -1
  244. package/dts/sparkline/sparkline-interactive/__stories__/SparklineInteractive.stories.d.ts +0 -3
  245. package/dts/sparkline/sparkline-interactive/__stories__/SparklineInteractive.stories.d.ts.map +0 -1
  246. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractive.test.d.ts +0 -2
  247. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractive.test.d.ts.map +0 -1
  248. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractiveHoverDate.test.d.ts +0 -2
  249. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractiveHoverDate.test.d.ts.map +0 -1
  250. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractivePanGestureHandler.test.d.ts +0 -2
  251. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractivePanGestureHandler.test.d.ts.map +0 -1
  252. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractivePeriodSelector.test.d.ts +0 -2
  253. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractivePeriodSelector.test.d.ts.map +0 -1
  254. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractiveTimeseriesPaths.test.d.ts +0 -2
  255. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractiveTimeseriesPaths.test.d.ts.map +0 -1
  256. package/dts/sparkline/sparkline-interactive/__tests__/useMinMaxTransform.test.d.ts +0 -2
  257. package/dts/sparkline/sparkline-interactive/__tests__/useMinMaxTransform.test.d.ts.map +0 -1
  258. package/dts/sparkline/sparkline-interactive/useInterruptiblePathAnimation.test.disable.d.ts +0 -2
  259. package/dts/sparkline/sparkline-interactive/useInterruptiblePathAnimation.test.disable.d.ts.map +0 -1
  260. package/dts/sparkline/sparkline-interactive-header/__stories__/SparklineInteractiveHeader.stories.d.ts +0 -4
  261. package/dts/sparkline/sparkline-interactive-header/__stories__/SparklineInteractiveHeader.stories.d.ts.map +0 -1
  262. package/dts/sparkline/sparkline-interactive-header/__tests__/SparklineInteractiveHeader.test.d.ts +0 -2
  263. package/dts/sparkline/sparkline-interactive-header/__tests__/SparklineInteractiveHeader.test.d.ts.map +0 -1
  264. package/dts/sparkline/sparkline-interactive-header/__tests__/useSparklineInteractiveHeaderStyles.test.d.ts +0 -2
  265. package/dts/sparkline/sparkline-interactive-header/__tests__/useSparklineInteractiveHeaderStyles.test.d.ts.map +0 -1
@@ -0,0 +1,270 @@
1
+ import { isSharedValue } from 'react-native-reanimated';
2
+ import { stack as d3Stack, stackOffsetDiverging, stackOrderNone } from 'd3-shape';
3
+ export const defaultStackId = 'DEFAULT_STACK_ID';
4
+ /**
5
+ * Type guard to check if bounds are complete with both min and max values.
6
+ * @param bounds - The bounds to validate
7
+ * @returns True if bounds has both min and max defined
8
+ */
9
+ export const isValidBounds = bounds => bounds.min !== undefined && bounds.max !== undefined;
10
+ /**
11
+ * Calculates the domain of a chart from series data.
12
+ * Domain represents the range of x-values from the data.
13
+ */
14
+ export const getChartDomain = (series, min, max) => {
15
+ const domain = {
16
+ min,
17
+ max
18
+ };
19
+ if (domain.min !== undefined && domain.max !== undefined) {
20
+ return domain;
21
+ }
22
+ if (series.length > 0) {
23
+ const dataLength = Math.max(...series.map(s => {
24
+ var _s$data;
25
+ return ((_s$data = s.data) == null ? void 0 : _s$data.length) || 0;
26
+ }));
27
+ if (dataLength > 0) {
28
+ if (domain.min === undefined) domain.min = 0;
29
+ if (domain.max === undefined) domain.max = dataLength - 1;
30
+ }
31
+ }
32
+ return domain;
33
+ };
34
+
35
+ /**
36
+ * Creates a composite stack key that includes both stack ID and y-axis ID.
37
+ * This ensures series with different y-scales don't get stacked together.
38
+ */
39
+ const createStackKey = series => {
40
+ if (series.stackId === undefined) return undefined;
41
+
42
+ // Include y-axis ID to prevent cross-scale stacking
43
+ const yAxisId = series.yAxisId || 'default';
44
+ return series.stackId + ":" + yAxisId;
45
+ };
46
+
47
+ /**
48
+ * Transforms series data into stacked data using D3's stack algorithm.
49
+ * Returns a map of series ID to transformed [baseline, value] tuples.
50
+ *
51
+ * @param series - Array of series with potential stack properties
52
+ * @returns Map of series ID to stacked data arrays
53
+ */
54
+ export const getStackedSeriesData = series => {
55
+ const stackedDataMap = new Map();
56
+ const numericStackGroups = new Map();
57
+ const individualSeries = [];
58
+ series.forEach(s => {
59
+ var _s$data2;
60
+ const stackKey = createStackKey(s);
61
+ const hasTupleData = (_s$data2 = s.data) == null ? void 0 : _s$data2.some(val => Array.isArray(val));
62
+ if (hasTupleData || stackKey === undefined) {
63
+ individualSeries.push(s);
64
+ } else {
65
+ if (!numericStackGroups.has(stackKey)) {
66
+ numericStackGroups.set(stackKey, []);
67
+ }
68
+ numericStackGroups.get(stackKey).push(s);
69
+ }
70
+ });
71
+ individualSeries.forEach(s => {
72
+ if (!s.data) return;
73
+ const normalizedData = s.data.map(val => {
74
+ if (val === null) return null;
75
+ if (Array.isArray(val)) {
76
+ return val;
77
+ }
78
+ if (typeof val === 'number') {
79
+ return [0, val];
80
+ }
81
+ return null;
82
+ });
83
+ stackedDataMap.set(s.id, normalizedData);
84
+ });
85
+ numericStackGroups.forEach((groupSeries, stackKey) => {
86
+ const maxLength = Math.max(...groupSeries.map(s => {
87
+ var _s$data3;
88
+ return ((_s$data3 = s.data) == null ? void 0 : _s$data3.length) || 0;
89
+ }));
90
+ if (maxLength === 0) return;
91
+ const dataset = new Array(maxLength).fill(undefined).map((_, i) => {
92
+ const row = {};
93
+ for (const s of groupSeries) {
94
+ var _s$data4;
95
+ const val = (_s$data4 = s.data) == null ? void 0 : _s$data4[i];
96
+ const num = typeof val === 'number' ? val : 0;
97
+ row[s.id] = num;
98
+ }
99
+ return row;
100
+ });
101
+ const keys = groupSeries.map(s => s.id);
102
+ const stackedSeries = d3Stack().keys(keys).order(stackOrderNone).offset(stackOffsetDiverging)(dataset);
103
+ stackedSeries.forEach((layer, layerIndex) => {
104
+ const seriesId = keys[layerIndex];
105
+ const stackedData = layer.map(_ref => {
106
+ let [bottom, top] = _ref;
107
+ return [bottom, top];
108
+ });
109
+ stackedDataMap.set(seriesId, stackedData);
110
+ });
111
+ });
112
+ return stackedDataMap;
113
+ };
114
+
115
+ /**
116
+ * Extracts line data values from series data that may contain tuples.
117
+ * For tuple data [[baseline, value]], extracts the last value.
118
+ * For numeric data [value], returns as-is.
119
+ *
120
+ * @param data - Array of numbers, tuples, or null values
121
+ * @returns Array of numbers or null values
122
+ */
123
+ export const getLineData = data => {
124
+ if (!data) return [];
125
+
126
+ // Check if this is tuple data by finding first non-null entry
127
+ const firstNonNull = data.find(d => d !== null);
128
+ if (Array.isArray(firstNonNull)) {
129
+ return data.map(d => {
130
+ var _d$at;
131
+ if (d === null) return null;
132
+ if (Array.isArray(d)) return (_d$at = d.at(-1)) != null ? _d$at : null;
133
+ return d;
134
+ });
135
+ }
136
+
137
+ // Already numeric data
138
+ return data;
139
+ };
140
+
141
+ /**
142
+ * Calculates the range of a chart from series data.
143
+ * Range represents the range of y-values from the data.
144
+ * Handles stacking by transforming data when series have stack properties.
145
+ */
146
+ export const getChartRange = (series, min, max) => {
147
+ const range = {
148
+ min,
149
+ max
150
+ };
151
+ if (range.min !== undefined && range.max !== undefined) {
152
+ return range;
153
+ }
154
+ if (series.length === 0) {
155
+ return range;
156
+ }
157
+
158
+ // Group series by composite stack key for proper calculation
159
+ const stackGroups = new Map();
160
+ series.forEach(s => {
161
+ const stackKey = createStackKey(s);
162
+ if (!stackGroups.has(stackKey)) {
163
+ stackGroups.set(stackKey, []);
164
+ }
165
+ stackGroups.get(stackKey).push(s);
166
+ });
167
+
168
+ // Check if we have any stacked series
169
+ const hasStacks = Array.from(stackGroups.keys()).some(k => k !== undefined);
170
+ if (hasStacks) {
171
+ // Get stacked data using the shared function
172
+ const stackedDataMap = getStackedSeriesData(series);
173
+
174
+ // Find the extreme values from the stacked data
175
+ let stackedMax = 0;
176
+ let stackedMin = 0;
177
+ stackedDataMap.forEach(stackedData => {
178
+ stackedData.forEach(point => {
179
+ if (point !== null) {
180
+ const [bottom, top] = point;
181
+ if (top > stackedMax) stackedMax = top;
182
+ if (bottom < stackedMin) stackedMin = bottom;
183
+ }
184
+ });
185
+ });
186
+
187
+ // Don't add padding - let D3's nice() function handle axis padding
188
+ if (range.min === undefined) range.min = Math.min(0, stackedMin);
189
+ if (range.max === undefined) range.max = Math.max(0, stackedMax);
190
+ } else {
191
+ // No stacking, calculate range from raw values
192
+ const allValues = [];
193
+ series.forEach(s => {
194
+ if (s.data) {
195
+ s.data.forEach(point => {
196
+ if (typeof point === 'number') {
197
+ allValues.push(point);
198
+ } else if (Array.isArray(point)) {
199
+ // Filter out null values from tuples
200
+ const validValues = point.filter(val => val !== null);
201
+ allValues.push(...validValues);
202
+ }
203
+ });
204
+ }
205
+ });
206
+ if (allValues.length > 0) {
207
+ const minValue = Math.min(...allValues);
208
+ const maxValue = Math.max(...allValues);
209
+ if (range.min === undefined) range.min = minValue;
210
+ if (range.max === undefined) range.max = maxValue;
211
+ }
212
+ }
213
+ return range;
214
+ };
215
+ export const defaultChartInset = {
216
+ top: 32,
217
+ left: 16,
218
+ bottom: 16,
219
+ right: 16
220
+ };
221
+
222
+ /**
223
+ * Normalize padding to include all sides with a value.
224
+ * @param padding - The padding to get.
225
+ * @param defaults - Optional complete default values to use instead of 0.
226
+ * @returns The calculated padding.
227
+ */
228
+ /**
229
+ * Normalize inset to include all sides with a value.
230
+ * @param inset - The inset to get.
231
+ * @param defaults - Optional complete default values to use instead of 0.
232
+ * @returns The calculated inset.
233
+ */
234
+ export const getChartInset = (inset, defaults) => {
235
+ var _inset$top, _inset$left, _inset$bottom, _inset$right;
236
+ const baseDefaults = defaults != null ? defaults : {
237
+ top: 0,
238
+ left: 0,
239
+ bottom: 0,
240
+ right: 0
241
+ };
242
+ if (typeof inset === 'number') {
243
+ return {
244
+ top: inset,
245
+ left: inset,
246
+ bottom: inset,
247
+ right: inset
248
+ };
249
+ }
250
+ return {
251
+ top: (_inset$top = inset == null ? void 0 : inset.top) != null ? _inset$top : baseDefaults.top,
252
+ left: (_inset$left = inset == null ? void 0 : inset.left) != null ? _inset$left : baseDefaults.left,
253
+ bottom: (_inset$bottom = inset == null ? void 0 : inset.bottom) != null ? _inset$bottom : baseDefaults.bottom,
254
+ right: (_inset$right = inset == null ? void 0 : inset.right) != null ? _inset$right : baseDefaults.right
255
+ };
256
+ };
257
+
258
+ /**
259
+ * Unwraps an optionally animated value to get the raw value.
260
+ * @param value - The value to unwrap.
261
+ * @returns The raw value.
262
+ */
263
+ export const unwrapAnimatedValue = value => {
264
+ 'worklet';
265
+
266
+ if (isSharedValue(value)) {
267
+ return value.value;
268
+ }
269
+ return value;
270
+ };
@@ -0,0 +1,15 @@
1
+ import { createContext, useContext } from 'react';
2
+
3
+ /**
4
+ * Context value for Cartesian (X/Y) coordinate charts.
5
+ * Contains axis-specific methods and properties for rectangular coordinate systems.
6
+ */
7
+
8
+ export const ScrubberContext = /*#__PURE__*/createContext(undefined);
9
+ export const useScrubberContext = () => {
10
+ const context = useContext(ScrubberContext);
11
+ if (!context) {
12
+ throw new Error('useScrubberContext must be used within a Chart component');
13
+ }
14
+ return context;
15
+ };
@@ -0,0 +1,305 @@
1
+ import { Skia } from '@shopify/react-native-skia';
2
+ import { applySerializableScale, isCategoricalScale, isSerializableScale } from './scale';
3
+
4
+ /**
5
+ * Defines a color transition point in the gradient
6
+ */
7
+
8
+ /**
9
+ * Defines a gradient.
10
+ */
11
+
12
+ /**
13
+ * Resolves gradient stops, handling both static arrays and function forms.
14
+ * When stops is a function, calls it with the domain bounds.
15
+ */
16
+ export const getGradientStops = (stops, domain) => {
17
+ if (typeof stops === 'function') {
18
+ return stops(domain);
19
+ }
20
+ return stops;
21
+ };
22
+
23
+ /**
24
+ * Processes Gradient to gradient configuration for SVG linearGradient.
25
+ * Colors are smoothly interpolated between stops by the browser.
26
+ * Multiple stops at the same offset create hard color transitions.
27
+ */
28
+ const processGradientStops = (stops, scale) => {
29
+ if (stops.length === 0) {
30
+ console.warn('Gradient has no stops - falling back to default');
31
+ return;
32
+ }
33
+
34
+ // Check if stops are in ascending order
35
+ const isOutOfOrder = stops.some((stop, i) => {
36
+ return i > 0 && stop.offset < stops[i - 1].offset;
37
+ });
38
+ if (isOutOfOrder) {
39
+ console.warn("Gradient: stop offsets must be in ascending order");
40
+ return;
41
+ }
42
+ const [rangeMin, rangeMax] = scale.range();
43
+ const rangeSpan = Math.abs(rangeMax - rangeMin);
44
+
45
+ // Convert data value offsets to normalized positions (0-1) using scale
46
+ const normalizedStops = stops.map(stop => {
47
+ var _stop$opacity;
48
+ const stopPosition = scale(stop.offset);
49
+ const normalized = stopPosition === undefined ? 0 : Math.max(0, Math.min(1, Math.abs(stopPosition - rangeMin) / rangeSpan));
50
+ return {
51
+ offset: normalized,
52
+ // Now 0-1 normalized (not data space)
53
+ color: stop.color,
54
+ opacity: (_stop$opacity = stop.opacity) != null ? _stop$opacity : 1
55
+ };
56
+ }).sort((a, b) => a.offset - b.offset);
57
+ return normalizedStops;
58
+ };
59
+
60
+ /**
61
+ * Interpolates between two colors using linear interpolation.
62
+ * Returns an rgba string.
63
+ */
64
+ const interpolateColor = (color1, color2, t) => {
65
+ 'worklet';
66
+
67
+ const c1 = Skia.Color(color1);
68
+ const c2 = Skia.Color(color2);
69
+ const r = Math.round((c1[0] + (c2[0] - c1[0]) * t) * 255);
70
+ const g = Math.round((c1[1] + (c2[1] - c1[1]) * t) * 255);
71
+ const b = Math.round((c1[2] + (c2[2] - c1[2]) * t) * 255);
72
+ const a = c1[3] + (c2[3] - c1[3]) * t;
73
+ return "rgba(" + r + ", " + g + ", " + b + ", " + a + ")";
74
+ };
75
+
76
+ /**
77
+ * Adds an opacity to a color
78
+ * Returns an rgba string.
79
+ */
80
+ export const getColorWithOpacity = (color1, opacity) => {
81
+ const c = Skia.Color(color1);
82
+ return "rgba(" + c[0] * 255 + ", " + c[1] * 255 + ", " + c[2] * 255 + ", " + opacity + ")";
83
+ };
84
+
85
+ /**
86
+ * Creates a gradient configuration for SVG components.
87
+ * Processes a GradientDefinition into a renderable GradientConfig.
88
+ * Supports both numeric scales (linear, log) and categorical scales (band).
89
+ *
90
+ * @param gradient - GradientDefinition configuration (required)
91
+ * @param xScale - X-axis scale (required)
92
+ * @param yScale - Y-axis scale (required)
93
+ * @returns GradientConfig or null if gradient processing fails
94
+ *
95
+ * @example
96
+ * const gradientConfig = useMemo(() => {
97
+ * if (!gradient || !xScale || !yScale) return;
98
+ * return getGradientConfig(gradient, xScale, yScale);
99
+ * }, [gradient, xScale, yScale]);
100
+ *
101
+ * if (gradientConfig) {
102
+ * return (
103
+ * <defs>
104
+ * <Gradient
105
+ * config={gradientConfig}
106
+ * direction={gradient.axis === 'x' ? 'horizontal' : 'vertical'}
107
+ * id={gradientId}
108
+ * />
109
+ * </defs>
110
+ * );
111
+ * }
112
+ */
113
+ export const getGradientConfig = (gradient, xScale, yScale) => {
114
+ if (!gradient) return;
115
+
116
+ // Get the scale based on axis
117
+ const scale = gradient.axis === 'x' ? xScale : yScale;
118
+ if (!scale) return;
119
+
120
+ // Extract domain from scale
121
+ const scaleDomain = scale.domain();
122
+ let domain;
123
+ if (isCategoricalScale(scale)) {
124
+ const domainArray = scaleDomain;
125
+ domain = {
126
+ min: domainArray[0],
127
+ max: domainArray[domainArray.length - 1]
128
+ };
129
+ } else {
130
+ const [min, max] = scaleDomain;
131
+ domain = {
132
+ min,
133
+ max
134
+ };
135
+ }
136
+ const resolvedStops = getGradientStops(gradient.stops, domain);
137
+ return processGradientStops(resolvedStops, scale);
138
+ };
139
+
140
+ /**
141
+ * Evaluates the color at a specific data value based on the gradient stops, ignoring opacity.
142
+ * @param stops - The gradient stops configuration
143
+ * @param dataValue - The data value to evaluate (for band scales, this is the index)
144
+ * @param scale - The scale to use for value mapping (handles log scales correctly)
145
+ * @returns The color string at this data value, or undefined if invalid
146
+ */
147
+ export const evaluateGradientAtValue = (stops, dataValue, scale) => {
148
+ 'worklet';
149
+
150
+ if (stops.length === 0) return;
151
+
152
+ // Determine range based on scale type
153
+ let rangeMin;
154
+ let rangeMax;
155
+ if (isSerializableScale(scale)) {
156
+ // SerializableScale has range as [number, number]
157
+ [rangeMin, rangeMax] = scale.range;
158
+ } else {
159
+ // ChartScaleFunction has range() method
160
+ const scaleRange = scale.range();
161
+ [rangeMin, rangeMax] = Array.isArray(scaleRange) ? scaleRange : [scaleRange, scaleRange]; // fallback for band scales
162
+ }
163
+ const rangeSpan = Math.abs(rangeMax - rangeMin);
164
+ if (rangeSpan === 0) return stops[0].color;
165
+
166
+ // Map dataValue through scale to get position
167
+ let dataPosition;
168
+ if (isSerializableScale(scale)) {
169
+ dataPosition = applySerializableScale(dataValue, scale);
170
+ } else {
171
+ const result = scale(dataValue);
172
+ if (result === undefined) return stops[0].color;
173
+ dataPosition = result;
174
+ }
175
+
176
+ // Normalize to 0-1 based on range
177
+ const normalizedValue = Math.max(0, Math.min(1, Math.abs(dataPosition - rangeMin) / rangeSpan));
178
+
179
+ // Map stop offsets through scale and normalize to 0-1
180
+ const positions = stops.map(stop => {
181
+ let stopPosition;
182
+ if (isSerializableScale(scale)) {
183
+ stopPosition = applySerializableScale(stop.offset, scale);
184
+ } else {
185
+ const result = scale(stop.offset);
186
+ if (result === undefined) return 0;
187
+ stopPosition = result;
188
+ }
189
+ return Math.max(0, Math.min(1, Math.abs(stopPosition - rangeMin) / rangeSpan));
190
+ });
191
+
192
+ // Find which segment we're in
193
+ if (normalizedValue < positions[0]) {
194
+ return stops[0].color;
195
+ }
196
+ if (normalizedValue >= positions[positions.length - 1]) {
197
+ return stops[stops.length - 1].color;
198
+ }
199
+
200
+ // Check if dataValue matches any stop offset exactly (for hard transitions)
201
+ for (let i = 0; i < stops.length; i++) {
202
+ if (dataValue === stops[i].offset) {
203
+ // Found exact match - check if there are multiple stops at this offset (hard transition)
204
+ // Use the LAST color at this offset for hard transitions
205
+ let lastIndexAtOffset = i;
206
+ while (lastIndexAtOffset + 1 < stops.length && stops[lastIndexAtOffset + 1].offset === stops[i].offset) {
207
+ lastIndexAtOffset++;
208
+ }
209
+ return stops[lastIndexAtOffset].color;
210
+ }
211
+ }
212
+
213
+ // Find the segment to interpolate between
214
+ for (let i = 0; i < positions.length - 1; i++) {
215
+ if (normalizedValue >= positions[i] && normalizedValue <= positions[i + 1]) {
216
+ const segmentStart = positions[i];
217
+ const segmentEnd = positions[i + 1];
218
+ if (segmentEnd === segmentStart) {
219
+ return stops[i].color;
220
+ }
221
+ const t = (normalizedValue - segmentStart) / (segmentEnd - segmentStart);
222
+ return interpolateColor(stops[i].color, stops[i + 1].color, t);
223
+ }
224
+ }
225
+ return stops[0].color;
226
+ };
227
+
228
+ /**
229
+ * Determines the baseline value for the gradient area by finding the value
230
+ * within the axis bounds that is closest to the target baseline.
231
+ *
232
+ * @param axisBounds - The min and max bounds of the axis
233
+ * @param baseline - The target baseline value (defaults to 0)
234
+ * @returns The value within bounds closest to the baseline
235
+ */
236
+ export const getBaseline = function (axisBounds, baseline) {
237
+ if (baseline === void 0) {
238
+ baseline = 0;
239
+ }
240
+ const {
241
+ min,
242
+ max
243
+ } = axisBounds;
244
+
245
+ // Normalize to ensure lowerBound <= upperBound
246
+ const lowerBound = Math.min(min, max);
247
+ const upperBound = Math.max(min, max);
248
+
249
+ // If baseline is within the range, use it
250
+ if (lowerBound <= baseline && baseline <= upperBound) return baseline;
251
+
252
+ // Otherwise, return the bound closest to baseline
253
+ return Math.abs(lowerBound - baseline) < Math.abs(upperBound - baseline) ? lowerBound : upperBound;
254
+ };
255
+
256
+ /**
257
+ * Generates a gradient definition for the area chart based on the axis bounds
258
+ * and styling parameters. Ensures gradient stops are in ascending order.
259
+ *
260
+ * @param axisBounds - The min and max bounds of the axis
261
+ * @param baselineValue - The baseline value for the gradient
262
+ * @param fill - The color to use for the gradient
263
+ * @param peakOpacity - Opacity at the peak of the gradient
264
+ * @param baselineOpacity - Opacity at the baseline
265
+ * @returns A gradient definition with y-axis stops in ascending order
266
+ */
267
+ export const createGradient = (axisBounds, baselineValue, fill, peakOpacity, baselineOpacity) => {
268
+ const {
269
+ min,
270
+ max
271
+ } = axisBounds;
272
+ const lowerBound = Math.min(min, max);
273
+ const upperBound = Math.max(min, max);
274
+ if (lowerBound < baselineValue && baselineValue < upperBound) {
275
+ return {
276
+ axis: 'y',
277
+ stops: [{
278
+ offset: lowerBound,
279
+ color: fill,
280
+ opacity: peakOpacity
281
+ }, {
282
+ offset: baselineValue,
283
+ color: fill,
284
+ opacity: baselineOpacity
285
+ }, {
286
+ offset: upperBound,
287
+ color: fill,
288
+ opacity: peakOpacity
289
+ }]
290
+ };
291
+ }
292
+ const peakValue = Math.abs(min - baselineValue) > Math.abs(max - baselineValue) ? min : max;
293
+ return {
294
+ axis: 'y',
295
+ stops: [{
296
+ offset: peakValue,
297
+ color: fill,
298
+ opacity: peakOpacity
299
+ }, {
300
+ offset: baselineValue,
301
+ color: fill,
302
+ opacity: baselineOpacity
303
+ }].sort((a, b) => a.offset - b.offset)
304
+ };
305
+ };
@@ -0,0 +1,12 @@
1
+ // codegen:start {preset: barrel, include: ./*.ts, exclude: ./__tests__/*.ts}
2
+ export * from './axis';
3
+ export * from './bar';
4
+ export * from './chart';
5
+ export * from './context';
6
+ export * from './gradient';
7
+ export * from './path';
8
+ export * from './point';
9
+ export * from './scale';
10
+ export * from './scrubber';
11
+ export * from './transition';
12
+ // codegen:end