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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (223) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/dts/chart/CartesianChart.d.ts +101 -0
  3. package/dts/chart/CartesianChart.d.ts.map +1 -0
  4. package/dts/chart/ChartProvider.d.ts +6 -0
  5. package/dts/chart/ChartProvider.d.ts.map +1 -0
  6. package/dts/chart/Path.d.ts +48 -0
  7. package/dts/chart/Path.d.ts.map +1 -0
  8. package/dts/chart/PeriodSelector.d.ts +85 -0
  9. package/dts/chart/PeriodSelector.d.ts.map +1 -0
  10. package/dts/chart/Point.d.ts +103 -0
  11. package/dts/chart/Point.d.ts.map +1 -0
  12. package/dts/chart/area/Area.d.ts +62 -0
  13. package/dts/chart/area/Area.d.ts.map +1 -0
  14. package/dts/chart/area/AreaChart.d.ts +90 -0
  15. package/dts/chart/area/AreaChart.d.ts.map +1 -0
  16. package/dts/chart/area/DottedArea.d.ts +27 -0
  17. package/dts/chart/area/DottedArea.d.ts.map +1 -0
  18. package/dts/chart/area/GradientArea.d.ts +30 -0
  19. package/dts/chart/area/GradientArea.d.ts.map +1 -0
  20. package/dts/chart/area/SolidArea.d.ts +8 -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 +204 -0
  25. package/dts/chart/axis/Axis.d.ts.map +1 -0
  26. package/dts/chart/axis/XAxis.d.ts +16 -0
  27. package/dts/chart/axis/XAxis.d.ts.map +1 -0
  28. package/dts/chart/axis/YAxis.d.ts +21 -0
  29. package/dts/chart/axis/YAxis.d.ts.map +1 -0
  30. package/dts/chart/axis/index.d.ts +4 -0
  31. package/dts/chart/axis/index.d.ts.map +1 -0
  32. package/dts/chart/bar/Bar.d.ts +89 -0
  33. package/dts/chart/bar/Bar.d.ts.map +1 -0
  34. package/dts/chart/bar/BarChart.d.ts +97 -0
  35. package/dts/chart/bar/BarChart.d.ts.map +1 -0
  36. package/dts/chart/bar/BarPlot.d.ts +29 -0
  37. package/dts/chart/bar/BarPlot.d.ts.map +1 -0
  38. package/dts/chart/bar/BarStack.d.ts +111 -0
  39. package/dts/chart/bar/BarStack.d.ts.map +1 -0
  40. package/dts/chart/bar/BarStackGroup.d.ts +35 -0
  41. package/dts/chart/bar/BarStackGroup.d.ts.map +1 -0
  42. package/dts/chart/bar/DefaultBar.d.ts +7 -0
  43. package/dts/chart/bar/DefaultBar.d.ts.map +1 -0
  44. package/dts/chart/bar/DefaultBarStack.d.ts +7 -0
  45. package/dts/chart/bar/DefaultBarStack.d.ts.map +1 -0
  46. package/dts/chart/bar/index.d.ts +8 -0
  47. package/dts/chart/bar/index.d.ts.map +1 -0
  48. package/dts/chart/index.d.ts +13 -0
  49. package/dts/chart/index.d.ts.map +1 -0
  50. package/dts/chart/line/DottedLine.d.ts +12 -0
  51. package/dts/chart/line/DottedLine.d.ts.map +1 -0
  52. package/dts/chart/line/GradientLine.d.ts +45 -0
  53. package/dts/chart/line/GradientLine.d.ts.map +1 -0
  54. package/dts/chart/line/Line.d.ts +78 -0
  55. package/dts/chart/line/Line.d.ts.map +1 -0
  56. package/dts/chart/line/LineChart.d.ts +84 -0
  57. package/dts/chart/line/LineChart.d.ts.map +1 -0
  58. package/dts/chart/line/ReferenceLine.d.ts +91 -0
  59. package/dts/chart/line/ReferenceLine.d.ts.map +1 -0
  60. package/dts/chart/line/SolidLine.d.ts +12 -0
  61. package/dts/chart/line/SolidLine.d.ts.map +1 -0
  62. package/dts/chart/line/index.d.ts +7 -0
  63. package/dts/chart/line/index.d.ts.map +1 -0
  64. package/dts/chart/scrubber/Scrubber.d.ts +104 -0
  65. package/dts/chart/scrubber/Scrubber.d.ts.map +1 -0
  66. package/dts/chart/scrubber/ScrubberBeacon.d.ts +75 -0
  67. package/dts/chart/scrubber/ScrubberBeacon.d.ts.map +1 -0
  68. package/dts/chart/scrubber/ScrubberProvider.d.ts +17 -0
  69. package/dts/chart/scrubber/ScrubberProvider.d.ts.map +1 -0
  70. package/dts/chart/scrubber/index.d.ts +2 -0
  71. package/dts/chart/scrubber/index.d.ts.map +1 -0
  72. package/dts/chart/text/ChartText.d.ts +90 -0
  73. package/dts/chart/text/ChartText.d.ts.map +1 -0
  74. package/dts/chart/text/SmartChartTextGroup.d.ts +55 -0
  75. package/dts/chart/text/SmartChartTextGroup.d.ts.map +1 -0
  76. package/dts/chart/text/index.d.ts +3 -0
  77. package/dts/chart/text/index.d.ts.map +1 -0
  78. package/dts/chart/utils/axis.d.ts +342 -0
  79. package/dts/chart/utils/axis.d.ts.map +1 -0
  80. package/dts/chart/utils/bar.d.ts +20 -0
  81. package/dts/chart/utils/bar.d.ts.map +1 -0
  82. package/dts/chart/utils/chart.d.ts +97 -0
  83. package/dts/chart/utils/chart.d.ts.map +1 -0
  84. package/dts/chart/utils/context.d.ts +95 -0
  85. package/dts/chart/utils/context.d.ts.map +1 -0
  86. package/dts/chart/utils/index.d.ts +8 -0
  87. package/dts/chart/utils/index.d.ts.map +1 -0
  88. package/dts/chart/utils/path.d.ts +107 -0
  89. package/dts/chart/utils/path.d.ts.map +1 -0
  90. package/dts/chart/utils/point.d.ts +75 -0
  91. package/dts/chart/utils/point.d.ts.map +1 -0
  92. package/dts/chart/utils/scale.d.ts +43 -0
  93. package/dts/chart/utils/scale.d.ts.map +1 -0
  94. package/dts/index.d.ts +2 -1
  95. package/dts/index.d.ts.map +1 -1
  96. package/dts/sparkline/Counter.d.ts +7 -2
  97. package/dts/sparkline/Sparkline.d.ts +67 -16
  98. package/dts/sparkline/Sparkline.d.ts.map +1 -1
  99. package/dts/sparkline/SparklineArea.d.ts +10 -4
  100. package/dts/sparkline/SparklineArea.d.ts.map +1 -1
  101. package/dts/sparkline/SparklineAreaPattern.d.ts +12 -4
  102. package/dts/sparkline/SparklineAreaPattern.d.ts.map +1 -1
  103. package/dts/sparkline/SparklineGradient.d.ts +21 -10
  104. package/dts/sparkline/SparklineGradient.d.ts.map +1 -1
  105. package/dts/sparkline/__figma__/Sparkline.figma.d.ts +1 -1
  106. package/dts/sparkline/generateSparklineWithId.d.ts +8 -2
  107. package/dts/sparkline/generateSparklineWithId.d.ts.map +1 -1
  108. package/dts/sparkline/index.d.ts +1 -1
  109. package/dts/sparkline/sparkline-interactive/SparklineAccessibleView.d.ts +8 -3
  110. package/dts/sparkline/sparkline-interactive/SparklineInteractive.d.ts +132 -110
  111. package/dts/sparkline/sparkline-interactive/SparklineInteractive.d.ts.map +1 -1
  112. package/dts/sparkline/sparkline-interactive/SparklineInteractiveAnimatedPath.d.ts +22 -9
  113. package/dts/sparkline/sparkline-interactive/SparklineInteractiveAnimatedPath.d.ts.map +1 -1
  114. package/dts/sparkline/sparkline-interactive/SparklineInteractiveHoverDate.d.ts +18 -7
  115. package/dts/sparkline/sparkline-interactive/SparklineInteractiveLineVertical.d.ts +9 -4
  116. package/dts/sparkline/sparkline-interactive/SparklineInteractiveMarkerDates.d.ts +11 -6
  117. package/dts/sparkline/sparkline-interactive/SparklineInteractiveMinMax.d.ts +7 -5
  118. package/dts/sparkline/sparkline-interactive/SparklineInteractivePanGestureHandler.d.ts +22 -10
  119. package/dts/sparkline/sparkline-interactive/SparklineInteractivePaths.d.ts +21 -7
  120. package/dts/sparkline/sparkline-interactive/SparklineInteractivePaths.d.ts.map +1 -1
  121. package/dts/sparkline/sparkline-interactive/SparklineInteractivePeriodSelector.d.ts +21 -16
  122. package/dts/sparkline/sparkline-interactive/SparklineInteractiveProvider.d.ts +29 -23
  123. package/dts/sparkline/sparkline-interactive/SparklineInteractiveTimeseriesPaths.d.ts +22 -14
  124. package/dts/sparkline/sparkline-interactive/__figma__/SparklineInteractive.figma.d.ts +1 -1
  125. package/dts/sparkline/sparkline-interactive/useInterruptiblePathAnimation.d.ts +9 -5
  126. package/dts/sparkline/sparkline-interactive/useMinMaxTransform.d.ts +11 -6
  127. package/dts/sparkline/sparkline-interactive/useOpacityAnimation.d.ts +5 -2
  128. package/dts/sparkline/sparkline-interactive/useSparklineInteractiveConstants.d.ts +17 -17
  129. package/dts/sparkline/sparkline-interactive/useSparklineInteractiveLineStyles.d.ts +16 -13
  130. package/dts/sparkline/sparkline-interactive-header/SparklineInteractiveHeader.d.ts +106 -98
  131. package/dts/sparkline/sparkline-interactive-header/__figma__/SparklineInteractiveHeader.figma.d.ts +1 -1
  132. package/dts/sparkline/sparkline-interactive-header/useSparklineInteractiveHeaderStyles.d.ts +22 -19
  133. package/esm/chart/CartesianChart.js +241 -0
  134. package/esm/chart/ChartProvider.js +10 -0
  135. package/esm/chart/Path.js +133 -0
  136. package/esm/chart/PeriodSelector.js +136 -0
  137. package/esm/chart/Point.js +111 -0
  138. package/esm/chart/__stories__/CartesianChart.stories.js +476 -0
  139. package/esm/chart/__stories__/Chart.stories.js +79 -0
  140. package/esm/chart/__stories__/PeriodSelector.stories.js +294 -0
  141. package/esm/chart/area/Area.js +85 -0
  142. package/esm/chart/area/AreaChart.js +146 -0
  143. package/esm/chart/area/DottedArea.js +128 -0
  144. package/esm/chart/area/GradientArea.js +110 -0
  145. package/esm/chart/area/SolidArea.js +24 -0
  146. package/esm/chart/area/__stories__/AreaChart.stories.js +100 -0
  147. package/esm/chart/area/index.js +7 -0
  148. package/esm/chart/axis/Axis.js +43 -0
  149. package/esm/chart/axis/XAxis.js +181 -0
  150. package/esm/chart/axis/YAxis.js +170 -0
  151. package/esm/chart/axis/__stories__/Axis.stories.js +277 -0
  152. package/esm/chart/axis/index.js +5 -0
  153. package/esm/chart/bar/Bar.js +67 -0
  154. package/esm/chart/bar/BarChart.js +147 -0
  155. package/esm/chart/bar/BarPlot.js +96 -0
  156. package/esm/chart/bar/BarStack.js +514 -0
  157. package/esm/chart/bar/BarStackGroup.js +89 -0
  158. package/esm/chart/bar/DefaultBar.js +78 -0
  159. package/esm/chart/bar/DefaultBarStack.js +82 -0
  160. package/esm/chart/bar/__stories__/BarChart.stories.js +282 -0
  161. package/esm/chart/bar/index.js +9 -0
  162. package/esm/chart/index.js +14 -0
  163. package/esm/chart/line/DottedLine.js +35 -0
  164. package/esm/chart/line/GradientLine.js +62 -0
  165. package/esm/chart/line/Line.js +139 -0
  166. package/esm/chart/line/LineChart.js +115 -0
  167. package/esm/chart/line/ReferenceLine.js +115 -0
  168. package/esm/chart/line/SolidLine.js +31 -0
  169. package/esm/chart/line/__stories__/LineChart.stories.js +2248 -0
  170. package/esm/chart/line/__stories__/ReferenceLine.stories.js +77 -0
  171. package/esm/chart/line/index.js +8 -0
  172. package/esm/chart/scrubber/Scrubber.js +186 -0
  173. package/esm/chart/scrubber/ScrubberBeacon.js +199 -0
  174. package/esm/chart/scrubber/ScrubberProvider.js +143 -0
  175. package/esm/chart/scrubber/index.js +2 -0
  176. package/esm/chart/text/ChartText.js +237 -0
  177. package/esm/chart/text/SmartChartTextGroup.js +210 -0
  178. package/esm/chart/text/index.js +4 -0
  179. package/esm/chart/utils/axis.js +592 -0
  180. package/esm/chart/utils/bar.js +24 -0
  181. package/esm/chart/utils/chart.js +229 -0
  182. package/esm/chart/utils/context.js +15 -0
  183. package/esm/chart/utils/index.js +9 -0
  184. package/esm/chart/utils/path.js +206 -0
  185. package/esm/chart/utils/point.js +118 -0
  186. package/esm/chart/utils/scale.js +48 -0
  187. package/esm/index.js +4 -1
  188. package/esm/sparkline/Sparkline.js +129 -16
  189. package/esm/sparkline/SparklineArea.js +7 -2
  190. package/esm/sparkline/SparklineAreaPattern.js +4 -2
  191. package/esm/sparkline/SparklineGradient.js +4 -0
  192. package/esm/sparkline/generateSparklineWithId.js +3 -2
  193. package/esm/sparkline/sparkline-interactive/SparklineInteractive.js +5 -1
  194. package/esm/sparkline/sparkline-interactive/SparklineInteractiveAnimatedPath.js +5 -2
  195. package/esm/sparkline/sparkline-interactive/SparklineInteractivePaths.js +4 -0
  196. package/esm/sparkline/sparkline-interactive/__stories__/SparklineInteractive.stories.js +27 -0
  197. package/package.json +11 -11
  198. package/dts/sparkline/__stories__/Sparkline.stories.d.ts +0 -3
  199. package/dts/sparkline/__stories__/Sparkline.stories.d.ts.map +0 -1
  200. package/dts/sparkline/__stories__/SparklineGradient.stories.d.ts +0 -3
  201. package/dts/sparkline/__stories__/SparklineGradient.stories.d.ts.map +0 -1
  202. package/dts/sparkline/sparkline-interactive/__stories__/SparklineInteractive.stories.d.ts +0 -3
  203. package/dts/sparkline/sparkline-interactive/__stories__/SparklineInteractive.stories.d.ts.map +0 -1
  204. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractive.test.d.ts +0 -2
  205. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractive.test.d.ts.map +0 -1
  206. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractiveHoverDate.test.d.ts +0 -2
  207. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractiveHoverDate.test.d.ts.map +0 -1
  208. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractivePanGestureHandler.test.d.ts +0 -2
  209. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractivePanGestureHandler.test.d.ts.map +0 -1
  210. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractivePeriodSelector.test.d.ts +0 -2
  211. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractivePeriodSelector.test.d.ts.map +0 -1
  212. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractiveTimeseriesPaths.test.d.ts +0 -2
  213. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractiveTimeseriesPaths.test.d.ts.map +0 -1
  214. package/dts/sparkline/sparkline-interactive/__tests__/useMinMaxTransform.test.d.ts +0 -2
  215. package/dts/sparkline/sparkline-interactive/__tests__/useMinMaxTransform.test.d.ts.map +0 -1
  216. package/dts/sparkline/sparkline-interactive/useInterruptiblePathAnimation.test.disable.d.ts +0 -2
  217. package/dts/sparkline/sparkline-interactive/useInterruptiblePathAnimation.test.disable.d.ts.map +0 -1
  218. package/dts/sparkline/sparkline-interactive-header/__stories__/SparklineInteractiveHeader.stories.d.ts +0 -4
  219. package/dts/sparkline/sparkline-interactive-header/__stories__/SparklineInteractiveHeader.stories.d.ts.map +0 -1
  220. package/dts/sparkline/sparkline-interactive-header/__tests__/SparklineInteractiveHeader.test.d.ts +0 -2
  221. package/dts/sparkline/sparkline-interactive-header/__tests__/SparklineInteractiveHeader.test.d.ts.map +0 -1
  222. package/dts/sparkline/sparkline-interactive-header/__tests__/useSparklineInteractiveHeaderStyles.test.d.ts +0 -2
  223. package/dts/sparkline/sparkline-interactive-header/__tests__/useSparklineInteractiveHeaderStyles.test.d.ts.map +0 -1
@@ -0,0 +1,241 @@
1
+ const _excluded = ["series", "animate", "enableScrubbing", "xAxis", "yAxis", "inset", "onScrubberPositionChange", "children", "width", "height", "style", "allowOverflowGestures"];
2
+ function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
3
+ function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
4
+ import React, { forwardRef, memo, useCallback, useMemo } from 'react';
5
+ import { Svg } from 'react-native-svg';
6
+ import { useLayout } from '@coinbase/cds-mobile/hooks/useLayout';
7
+ import { Box } from '@coinbase/cds-mobile/layout';
8
+ import { ScrubberProvider } from './scrubber/ScrubberProvider';
9
+ import { CartesianChartProvider } from './ChartProvider';
10
+ import { defaultAxisId, defaultChartInset, getAxisConfig, getAxisDomain, getAxisRange, getAxisScale, getChartInset, getStackedSeriesData as calculateStackedSeriesData, useTotalAxisPadding } from './utils';
11
+ import { jsx as _jsx } from "react/jsx-runtime";
12
+ export const CartesianChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) => {
13
+ let {
14
+ series,
15
+ animate = true,
16
+ enableScrubbing,
17
+ xAxis: xAxisConfigInput,
18
+ yAxis: yAxisConfigInput,
19
+ inset: insetInput,
20
+ onScrubberPositionChange,
21
+ children,
22
+ width = '100%',
23
+ height = '100%',
24
+ style,
25
+ allowOverflowGestures
26
+ } = _ref,
27
+ props = _objectWithoutPropertiesLoose(_ref, _excluded);
28
+ const [containerLayout, onContainerLayout] = useLayout();
29
+ const chartWidth = typeof width === 'number' ? width : containerLayout.width;
30
+ const chartHeight = typeof height === 'number' ? height : containerLayout.height;
31
+ const userInset = useMemo(() => {
32
+ return getChartInset(insetInput, defaultChartInset);
33
+ }, [insetInput]);
34
+
35
+ // there can only be one x axis but the helper function always returns an array
36
+ const xAxisConfig = useMemo(() => getAxisConfig('x', xAxisConfigInput)[0], [xAxisConfigInput]);
37
+ const yAxisConfig = useMemo(() => getAxisConfig('y', yAxisConfigInput), [yAxisConfigInput]);
38
+ const {
39
+ renderedAxes,
40
+ registerAxis,
41
+ unregisterAxis,
42
+ axisPadding
43
+ } = useTotalAxisPadding();
44
+ const totalInset = useMemo(() => ({
45
+ top: userInset.top + axisPadding.top,
46
+ right: userInset.right + axisPadding.right,
47
+ bottom: userInset.bottom + axisPadding.bottom,
48
+ left: userInset.left + axisPadding.left
49
+ }), [userInset, axisPadding]);
50
+ const chartRect = useMemo(() => {
51
+ if (chartWidth <= 0 || chartHeight <= 0) return {
52
+ x: 0,
53
+ y: 0,
54
+ width: 0,
55
+ height: 0
56
+ };
57
+ const availableWidth = chartWidth - totalInset.left - totalInset.right;
58
+ const availableHeight = chartHeight - totalInset.top - totalInset.bottom;
59
+ return {
60
+ x: totalInset.left,
61
+ y: totalInset.top,
62
+ width: availableWidth > 0 ? availableWidth : 0,
63
+ height: availableHeight > 0 ? availableHeight : 0
64
+ };
65
+ }, [chartHeight, chartWidth, totalInset]);
66
+ const xAxis = useMemo(() => {
67
+ if (!chartRect || chartRect.width <= 0 || chartRect.height <= 0) return undefined;
68
+ const domain = getAxisDomain(xAxisConfig, series != null ? series : [], 'x');
69
+ const range = getAxisRange(xAxisConfig, chartRect, 'x');
70
+ const axisConfig = {
71
+ scaleType: xAxisConfig.scaleType,
72
+ domain,
73
+ range,
74
+ data: xAxisConfig.data,
75
+ categoryPadding: xAxisConfig.categoryPadding,
76
+ domainLimit: xAxisConfig.domainLimit
77
+ };
78
+ return axisConfig;
79
+ }, [xAxisConfig, series, chartRect]);
80
+ const yAxes = useMemo(() => {
81
+ const axes = new Map();
82
+ if (!chartRect || chartRect.width <= 0 || chartRect.height <= 0) return axes;
83
+ yAxisConfig.forEach(axisParam => {
84
+ var _axisParam$id, _series$filter, _axisParam$domainLimi;
85
+ const axisId = (_axisParam$id = axisParam.id) != null ? _axisParam$id : defaultAxisId;
86
+
87
+ // Get relevant series data
88
+ const relevantSeries = (_series$filter = series == null ? void 0 : series.filter(s => {
89
+ var _s$yAxisId;
90
+ return ((_s$yAxisId = s.yAxisId) != null ? _s$yAxisId : defaultAxisId) === axisId;
91
+ })) != null ? _series$filter : [];
92
+
93
+ // Calculate domain and range in one pass
94
+ const domain = getAxisDomain(axisParam, relevantSeries, 'y');
95
+ const range = getAxisRange(axisParam, chartRect, 'y');
96
+ axes.set(axisId, {
97
+ scaleType: axisParam.scaleType,
98
+ domain,
99
+ range,
100
+ data: axisParam.data,
101
+ categoryPadding: axisParam.categoryPadding,
102
+ domainLimit: (_axisParam$domainLimi = axisParam.domainLimit) != null ? _axisParam$domainLimi : 'nice'
103
+ });
104
+ });
105
+ return axes;
106
+ }, [yAxisConfig, series, chartRect]);
107
+ const xScale = useMemo(() => {
108
+ if (!chartRect || chartRect.width <= 0 || chartRect.height <= 0 || xAxis === undefined) return undefined;
109
+ return getAxisScale({
110
+ config: xAxis,
111
+ type: 'x',
112
+ range: xAxis.range,
113
+ dataDomain: xAxis.domain
114
+ });
115
+ }, [chartRect, xAxis]);
116
+ const yScales = useMemo(() => {
117
+ const scales = new Map();
118
+ if (!chartRect || chartRect.width <= 0 || chartRect.height <= 0) return scales;
119
+ yAxes.forEach((axisConfig, axisId) => {
120
+ const scale = getAxisScale({
121
+ config: axisConfig,
122
+ type: 'y',
123
+ range: axisConfig.range,
124
+ dataDomain: axisConfig.domain
125
+ });
126
+ if (scale) {
127
+ scales.set(axisId, scale);
128
+ }
129
+ });
130
+ return scales;
131
+ }, [chartRect, yAxes]);
132
+ const getXAxis = useCallback(() => xAxis, [xAxis]);
133
+ const getYAxis = useCallback(id => yAxes.get(id != null ? id : defaultAxisId), [yAxes]);
134
+ const getXScale = useCallback(() => xScale, [xScale]);
135
+ const getYScale = useCallback(id => yScales.get(id != null ? id : defaultAxisId), [yScales]);
136
+ const getSeries = useCallback(seriesId => series == null ? void 0 : series.find(s => s.id === seriesId), [series]);
137
+
138
+ // Compute stacked data for series with stack properties
139
+ const stackedDataMap = useMemo(() => {
140
+ if (!series) return new Map();
141
+ return calculateStackedSeriesData(series);
142
+ }, [series]);
143
+ const getStackedSeriesData = useCallback(seriesId => {
144
+ if (!seriesId) return undefined;
145
+ return stackedDataMap.get(seriesId);
146
+ }, [stackedDataMap]);
147
+ const getAxisBounds = useCallback(axisId => {
148
+ const axis = renderedAxes.get(axisId);
149
+ if (!axis || !chartRect) return;
150
+ const axesAtPosition = Array.from(renderedAxes.values()).filter(a => a.position === axis.position).sort((a, b) => a.id.localeCompare(b.id));
151
+ const axisIndex = axesAtPosition.findIndex(a => a.id === axisId);
152
+ if (axisIndex === -1) return;
153
+
154
+ // Calculate offset from previous axes at the same position
155
+ const offsetFromPreviousAxes = axesAtPosition.slice(0, axisIndex).reduce((sum, a) => sum + a.size, 0);
156
+ if (axis.position === 'top') {
157
+ // Position above the chart rect, accounting for user inset
158
+ const startY = userInset.top + offsetFromPreviousAxes;
159
+ return {
160
+ x: chartRect.x,
161
+ y: startY,
162
+ width: chartRect.width,
163
+ height: axis.size
164
+ };
165
+ } else if (axis.position === 'bottom') {
166
+ // Position below the chart rect, accounting for user inset
167
+ const startY = chartRect.y + chartRect.height + offsetFromPreviousAxes;
168
+ return {
169
+ x: chartRect.x,
170
+ y: startY,
171
+ width: chartRect.width,
172
+ height: axis.size
173
+ };
174
+ } else if (axis.position === 'left') {
175
+ // Position to the left of the chart rect, accounting for user inset
176
+ const startX = userInset.left + offsetFromPreviousAxes;
177
+ return {
178
+ x: startX,
179
+ y: chartRect.y,
180
+ width: axis.size,
181
+ height: chartRect.height
182
+ };
183
+ } else {
184
+ // right - position to the right of the chart rect, accounting for user inset
185
+ const startX = chartRect.x + chartRect.width + offsetFromPreviousAxes;
186
+ return {
187
+ x: startX,
188
+ y: chartRect.y,
189
+ width: axis.size,
190
+ height: chartRect.height
191
+ };
192
+ }
193
+ }, [renderedAxes, chartRect, userInset]);
194
+ const contextValue = useMemo(() => ({
195
+ series: series != null ? series : [],
196
+ getSeries,
197
+ getSeriesData: getStackedSeriesData,
198
+ animate,
199
+ width: chartWidth,
200
+ height: chartHeight,
201
+ getXAxis,
202
+ getYAxis,
203
+ getXScale,
204
+ getYScale,
205
+ drawingArea: chartRect,
206
+ registerAxis,
207
+ unregisterAxis,
208
+ getAxisBounds
209
+ }), [series, getSeries, getStackedSeriesData, animate, chartWidth, chartHeight, getXAxis, getYAxis, getXScale, getYScale, chartRect, registerAxis, unregisterAxis, getAxisBounds]);
210
+ const containerStyles = useMemo(() => {
211
+ const dynamicStyles = {};
212
+ if (typeof width === 'string') {
213
+ dynamicStyles.width = width;
214
+ }
215
+ if (typeof height === 'string') {
216
+ dynamicStyles.height = height;
217
+ }
218
+ return [style, dynamicStyles];
219
+ }, [style, width, height]);
220
+ return /*#__PURE__*/_jsx(CartesianChartProvider, {
221
+ value: contextValue,
222
+ children: /*#__PURE__*/_jsx(ScrubberProvider, {
223
+ allowOverflowGestures: allowOverflowGestures,
224
+ enableScrubbing: enableScrubbing,
225
+ onScrubberPositionChange: onScrubberPositionChange,
226
+ children: /*#__PURE__*/_jsx(Box, _extends({
227
+ ref: ref,
228
+ accessibilityLiveRegion: "polite",
229
+ accessibilityRole: "image",
230
+ onLayout: onContainerLayout,
231
+ style: containerStyles
232
+ }, props, {
233
+ children: /*#__PURE__*/_jsx(Svg, {
234
+ height: chartHeight,
235
+ width: chartWidth,
236
+ children: children
237
+ })
238
+ }))
239
+ })
240
+ });
241
+ }));
@@ -0,0 +1,10 @@
1
+ import { createContext, useContext } from 'react';
2
+ const CartesianChartContext = /*#__PURE__*/createContext(undefined);
3
+ export const useCartesianChartContext = () => {
4
+ const context = useContext(CartesianChartContext);
5
+ if (!context) {
6
+ throw new Error('useCartesianChartContext must be used within a CartesianChart component. See http://cds.coinbase.com/components/graphs/CartesianChart.');
7
+ }
8
+ return context;
9
+ };
10
+ export const CartesianChartProvider = CartesianChartContext.Provider;
@@ -0,0 +1,133 @@
1
+ const _excluded = ["clipRect", "clipOffset", "d", "fill", "stroke", "strokeWidth", "strokeOpacity", "fillOpacity", "strokeDasharray", "testID", "animate"];
2
+ function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
3
+ function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
4
+ import { memo, useCallback, useEffect, useId, useMemo, useRef } from 'react';
5
+ import Reanimated, { runOnJS, useAnimatedProps, useAnimatedReaction, useSharedValue, withTiming } from 'react-native-reanimated';
6
+ import { ClipPath, Defs, G, Path as SvgPath, Rect } from 'react-native-svg';
7
+ import { usePreviousValue } from '@coinbase/cds-common/hooks/usePreviousValue';
8
+ import * as interpolate from 'd3-interpolate-path';
9
+ import { useCartesianChartContext } from './ChartProvider';
10
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
+ const AnimatedRect = Reanimated.createAnimatedComponent(Rect);
12
+ const AnimatedSvgRect = /*#__PURE__*/memo(_ref => {
13
+ let {
14
+ width,
15
+ totalOffset,
16
+ rectProps
17
+ } = _ref;
18
+ const animatedWidth = useSharedValue(width + totalOffset);
19
+ const animatedProps = useAnimatedProps(() => {
20
+ return {
21
+ width: animatedWidth.value
22
+ };
23
+ });
24
+ useEffect(() => {
25
+ animatedWidth.value = withTiming(width + totalOffset, {
26
+ duration: 1000
27
+ });
28
+ }, [animatedWidth, width, totalOffset]);
29
+ return /*#__PURE__*/_jsx(AnimatedRect, _extends({
30
+ animatedProps: animatedProps
31
+ }, rectProps));
32
+ });
33
+ export const Path = /*#__PURE__*/memo(_ref2 => {
34
+ let {
35
+ clipRect,
36
+ clipOffset,
37
+ d = '',
38
+ fill,
39
+ stroke,
40
+ strokeWidth,
41
+ strokeOpacity,
42
+ fillOpacity,
43
+ strokeDasharray,
44
+ testID,
45
+ animate: animateProp
46
+ } = _ref2,
47
+ pathProps = _objectWithoutPropertiesLoose(_ref2, _excluded);
48
+ const pathRef = useRef(null);
49
+ const {
50
+ animate: animateContext,
51
+ drawingArea: contextRect
52
+ } = useCartesianChartContext();
53
+ const rect = clipRect != null ? clipRect : contextRect;
54
+ const animate = animateProp != null ? animateProp : animateContext;
55
+ const clipPathId = useId();
56
+ const animationProgress = useSharedValue(0);
57
+ const targetPath = useMemo(() => d, [d]);
58
+ const previousPath = usePreviousValue(targetPath);
59
+ const fromPath = useMemo(() => {
60
+ if (!animate) return targetPath;
61
+ return previousPath != null ? previousPath : targetPath;
62
+ }, [animate, previousPath, targetPath]);
63
+ const pathInterpolator = useMemo(() => interpolate.interpolatePath(fromPath, targetPath), [fromPath, targetPath]);
64
+ const updatePath = useCallback(progress => {
65
+ var _pathRef$current;
66
+ if (!pathInterpolator) return;
67
+ const val = Number(progress.toFixed(4));
68
+ (_pathRef$current = pathRef.current) == null || _pathRef$current.setNativeProps({
69
+ d: pathInterpolator(val)
70
+ });
71
+ }, [pathInterpolator]);
72
+ useAnimatedReaction(() => animationProgress.value, progress => {
73
+ 'worklet';
74
+
75
+ runOnJS(updatePath)(progress);
76
+ }, [updatePath]);
77
+ useEffect(() => {
78
+ if (!pathRef.current) return;
79
+ if (!animate || !pathInterpolator) {
80
+ pathRef.current.setNativeProps({
81
+ d: targetPath
82
+ });
83
+ animationProgress.value = 1;
84
+ return;
85
+ }
86
+ animationProgress.value = 0;
87
+ animationProgress.value = withTiming(1, {
88
+ duration: 200
89
+ });
90
+ }, [animate, animationProgress, targetPath, pathInterpolator]);
91
+ if (!d || !rect) return;
92
+
93
+ // The clip offset provides extra padding to prevent path from being cut off
94
+ // Area charts typically use offset=0 for exact clipping, while lines use offset=2 for breathing room
95
+ const totalOffset = (clipOffset != null ? clipOffset : 0) * 2; // Applied on both sides
96
+
97
+ return /*#__PURE__*/_jsxs(G, {
98
+ children: [/*#__PURE__*/_jsx(Defs, {
99
+ children: animate ? /*#__PURE__*/_jsx(ClipPath, {
100
+ id: clipPathId,
101
+ children: /*#__PURE__*/_jsx(AnimatedSvgRect, {
102
+ rectProps: {
103
+ height: rect.height + totalOffset,
104
+ x: rect.x - (clipOffset != null ? clipOffset : 0),
105
+ y: rect.y - (clipOffset != null ? clipOffset : 0)
106
+ },
107
+ totalOffset: totalOffset,
108
+ width: rect.width
109
+ })
110
+ }) : /*#__PURE__*/_jsx(ClipPath, {
111
+ id: clipPathId,
112
+ children: /*#__PURE__*/_jsx(Rect, {
113
+ height: contextRect.height + totalOffset,
114
+ width: contextRect.width + totalOffset,
115
+ x: contextRect.x - (clipOffset != null ? clipOffset : 0),
116
+ y: contextRect.y - (clipOffset != null ? clipOffset : 0)
117
+ })
118
+ })
119
+ }), /*#__PURE__*/_jsx(SvgPath, _extends({
120
+ ref: pathRef,
121
+ clipPath: "url(#" + clipPathId + ")",
122
+ clipRule: "nonzero",
123
+ d: fromPath,
124
+ fill: fill,
125
+ fillOpacity: fillOpacity,
126
+ stroke: stroke,
127
+ strokeDasharray: strokeDasharray,
128
+ strokeOpacity: strokeOpacity,
129
+ strokeWidth: strokeWidth,
130
+ testID: testID
131
+ }, pathProps))]
132
+ });
133
+ });
@@ -0,0 +1,136 @@
1
+ const _excluded = ["color", "label", "font", "hideDot", "style"],
2
+ _excluded2 = ["background", "activeBackground", "width", "justifyContent", "TabComponent", "TabsActiveIndicatorComponent"];
3
+ function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
4
+ function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
5
+ import React, { forwardRef, memo, useMemo } from 'react';
6
+ import { StyleSheet, View } from 'react-native';
7
+ import Animated, { useAnimatedStyle, useSharedValue, withSpring } from 'react-native-reanimated';
8
+ import { useTheme } from '@coinbase/cds-mobile/hooks/useTheme';
9
+ import { SegmentedTabs } from '@coinbase/cds-mobile/tabs';
10
+ import { SegmentedTab } from '@coinbase/cds-mobile/tabs/SegmentedTab';
11
+ import { tabsSpringConfig } from '@coinbase/cds-mobile/tabs/Tabs';
12
+ import { Text } from '@coinbase/cds-mobile/typography/Text';
13
+
14
+ // Animated active indicator to support smooth transition of background color
15
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
16
+ export const PeriodSelectorActiveIndicator = _ref => {
17
+ let {
18
+ activeTabRect,
19
+ background = 'bgPrimaryWash',
20
+ position = 'absolute',
21
+ borderRadius = 1000
22
+ } = _ref;
23
+ const theme = useTheme();
24
+ const {
25
+ width,
26
+ height,
27
+ x
28
+ } = activeTabRect;
29
+
30
+ // Get the target background color
31
+ const backgroundColorKey = background;
32
+ const targetColor = theme.color[backgroundColorKey] || background;
33
+
34
+ // Track previous values for first render detection
35
+ const previousActiveTabRect = React.useRef(activeTabRect);
36
+ const previousColor = React.useRef(targetColor);
37
+
38
+ // Combined animated value for position, size, and color
39
+ const newAnimatedValues = {
40
+ x,
41
+ width,
42
+ backgroundColor: targetColor
43
+ };
44
+ const animatedValues = useSharedValue(newAnimatedValues);
45
+ const isFirstRenderWithWidth = previousActiveTabRect.current.width === 0 && activeTabRect.width > 0;
46
+ if (previousActiveTabRect.current !== activeTabRect || previousColor.current !== targetColor) {
47
+ previousActiveTabRect.current = activeTabRect;
48
+ previousColor.current = targetColor;
49
+ animatedValues.value = isFirstRenderWithWidth ? newAnimatedValues : withSpring(newAnimatedValues, tabsSpringConfig);
50
+ }
51
+ const animatedStyles = useAnimatedStyle(() => ({
52
+ transform: [{
53
+ translateX: animatedValues.value.x
54
+ }],
55
+ width: animatedValues.value.width,
56
+ backgroundColor: animatedValues.value.backgroundColor
57
+ }), [animatedValues]);
58
+ if (!width) return null;
59
+ return /*#__PURE__*/_jsx(Animated.View, {
60
+ style: [{
61
+ position: position,
62
+ height,
63
+ borderRadius
64
+ }, animatedStyles],
65
+ testID: "period-selector-active-indicator"
66
+ });
67
+ };
68
+ const styles = StyleSheet.create({
69
+ liveContainer: {
70
+ flexDirection: 'row',
71
+ alignItems: 'center'
72
+ }
73
+ });
74
+ export const LiveTabLabel = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref2, ref) => {
75
+ let {
76
+ color = 'fgNegative',
77
+ label = 'LIVE',
78
+ font = 'label1',
79
+ hideDot,
80
+ style
81
+ } = _ref2,
82
+ props = _objectWithoutPropertiesLoose(_ref2, _excluded);
83
+ const theme = useTheme();
84
+ const colorKey = color;
85
+ const textColor = theme.color[colorKey] || color;
86
+ const dotStyle = useMemo(() => ({
87
+ width: theme.space[1],
88
+ height: theme.space[1],
89
+ borderRadius: 1000,
90
+ marginRight: theme.space[0.75],
91
+ backgroundColor: textColor
92
+ }), [theme.space, textColor]);
93
+ return /*#__PURE__*/_jsxs(View, {
94
+ ref: ref,
95
+ style: [styles.liveContainer, style],
96
+ children: [!hideDot && /*#__PURE__*/_jsx(View, {
97
+ style: dotStyle
98
+ }), /*#__PURE__*/_jsx(Text, _extends({
99
+ color: color,
100
+ font: font
101
+ }, props, {
102
+ children: label
103
+ }))]
104
+ });
105
+ }));
106
+
107
+ // Custom tab component with primary color for active state
108
+ const PeriodSelectorTab = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((props, ref) => /*#__PURE__*/_jsx(SegmentedTab, _extends({
109
+ ref: ref,
110
+ activeColor: "fgPrimary",
111
+ font: "label1"
112
+ }, props))));
113
+ /**
114
+ * PeriodSelector is a specialized version of SegmentedTabs optimized for chart period selection.
115
+ * It provides transparent background, primary wash active state, and full-width layout by default.
116
+ */
117
+ export const PeriodSelector = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref3, ref) => {
118
+ let {
119
+ background = 'transparent',
120
+ activeBackground = 'bgPrimaryWash',
121
+ width = '100%',
122
+ justifyContent = 'space-between',
123
+ TabComponent = PeriodSelectorTab,
124
+ TabsActiveIndicatorComponent = PeriodSelectorActiveIndicator
125
+ } = _ref3,
126
+ props = _objectWithoutPropertiesLoose(_ref3, _excluded2);
127
+ return /*#__PURE__*/_jsx(SegmentedTabs, _extends({
128
+ ref: ref,
129
+ TabComponent: TabComponent,
130
+ TabsActiveIndicatorComponent: TabsActiveIndicatorComponent,
131
+ activeBackground: activeBackground,
132
+ background: background,
133
+ justifyContent: justifyContent,
134
+ width: width
135
+ }, props));
136
+ }));
@@ -0,0 +1,111 @@
1
+ function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
2
+ import { memo, useEffect, useMemo } from 'react';
3
+ import { Circle, G } from 'react-native-svg';
4
+ import { useTheme } from '@coinbase/cds-mobile/hooks/useTheme';
5
+ import { useCartesianChartContext } from './ChartProvider';
6
+ import { ChartText } from './text';
7
+ import { projectPoint, useScrubberContext } from './utils';
8
+
9
+ /**
10
+ * Parameters passed to renderPoints callback function.
11
+ */
12
+
13
+ /**
14
+ * Shared configuration for point appearance and behavior.
15
+ * Used by line-associated points rendered via Line/LineChart components.
16
+ */
17
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
18
+ export const Point = /*#__PURE__*/memo(_ref => {
19
+ let {
20
+ dataX,
21
+ dataY,
22
+ yAxisId,
23
+ fill,
24
+ radius = 4,
25
+ opacity,
26
+ onPress,
27
+ onScrubberEnter,
28
+ stroke,
29
+ strokeWidth = 2,
30
+ accessibilityLabel,
31
+ label,
32
+ labelProps,
33
+ pixelCoordinates,
34
+ testID
35
+ } = _ref;
36
+ const theme = useTheme();
37
+ const effectiveStroke = stroke != null ? stroke : theme.color.bg;
38
+ const {
39
+ getXScale,
40
+ getYScale
41
+ } = useCartesianChartContext();
42
+ const {
43
+ scrubberPosition
44
+ } = useScrubberContext();
45
+ const xScale = getXScale();
46
+ const yScale = getYScale(yAxisId);
47
+
48
+ // Scrubber detection: check if this point is highlighted by the scrubber
49
+ const isScrubberHighlighted = scrubberPosition !== undefined && scrubberPosition === dataX;
50
+
51
+ // Use provided pixelCoordinates or calculate from data coordinates
52
+ const pixelCoordinate = useMemo(() => {
53
+ if (pixelCoordinates) {
54
+ return pixelCoordinates;
55
+ }
56
+ if (!xScale || !yScale) {
57
+ return {
58
+ x: 0,
59
+ y: 0
60
+ };
61
+ }
62
+ return projectPoint({
63
+ x: dataX,
64
+ y: dataY,
65
+ xScale,
66
+ yScale
67
+ });
68
+ }, [pixelCoordinates, xScale, yScale, dataX, dataY]);
69
+ useEffect(() => {
70
+ if (isScrubberHighlighted && onScrubberEnter) {
71
+ onScrubberEnter({
72
+ x: pixelCoordinate.x,
73
+ y: pixelCoordinate.y
74
+ });
75
+ }
76
+ }, [isScrubberHighlighted, onScrubberEnter, pixelCoordinate.x, pixelCoordinate.y]);
77
+ if (!xScale || !yScale) {
78
+ return null;
79
+ }
80
+ return /*#__PURE__*/_jsxs(_Fragment, {
81
+ children: [/*#__PURE__*/_jsx(G, {
82
+ opacity: opacity,
83
+ testID: testID,
84
+ transform: [{
85
+ translateX: pixelCoordinate.x
86
+ }, {
87
+ translateY: pixelCoordinate.y
88
+ }],
89
+ children: /*#__PURE__*/_jsx(Circle, {
90
+ accessibilityLabel: accessibilityLabel,
91
+ cx: 0,
92
+ cy: 0,
93
+ fill: fill != null ? fill : theme.color.fgPrimary,
94
+ onPress: onPress ? event => onPress({
95
+ dataX,
96
+ dataY,
97
+ x: pixelCoordinate.x,
98
+ y: pixelCoordinate.y
99
+ }) : undefined,
100
+ r: radius,
101
+ stroke: effectiveStroke,
102
+ strokeWidth: strokeWidth
103
+ })
104
+ }), label && /*#__PURE__*/_jsx(ChartText, _extends({
105
+ x: pixelCoordinate.x,
106
+ y: pixelCoordinate.y
107
+ }, labelProps, {
108
+ children: label
109
+ }))]
110
+ });
111
+ });