@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,2248 @@
1
+ const _excluded = ["label"],
2
+ _excluded2 = ["label"],
3
+ _excluded3 = ["style"],
4
+ _excluded4 = ["dataX"];
5
+ 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; }
6
+ 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); }
7
+ import { forwardRef, memo, useCallback, useEffect, useId, useImperativeHandle, useMemo, useRef, useState } from 'react';
8
+ import { Defs, LinearGradient, Stop } from 'react-native-svg';
9
+ import { assets } from '@coinbase/cds-common/internal/data/assets';
10
+ import { candles as btcCandles } from '@coinbase/cds-common/internal/data/candles';
11
+ import { prices } from '@coinbase/cds-common/internal/data/prices';
12
+ import { sparklineInteractiveData } from '@coinbase/cds-common/internal/visualizations/SparklineInteractiveData';
13
+ import { useTabsContext } from '@coinbase/cds-common/tabs/TabsContext';
14
+ import { useTheme } from '@coinbase/cds-mobile';
15
+ import { Button } from '@coinbase/cds-mobile/buttons';
16
+ import { Example, ExampleScreen } from '@coinbase/cds-mobile/examples/ExampleScreen';
17
+ import { Box, HStack, VStack } from '@coinbase/cds-mobile/layout';
18
+ import { RemoteImage } from '@coinbase/cds-mobile/media';
19
+ import { SectionHeader } from '@coinbase/cds-mobile/section-header/SectionHeader';
20
+ import { SegmentedTabs } from '@coinbase/cds-mobile/tabs';
21
+ import { SegmentedTab } from '@coinbase/cds-mobile/tabs/SegmentedTab';
22
+ import { TextLabel1 } from '@coinbase/cds-mobile/typography';
23
+ import { Text } from '@coinbase/cds-mobile/typography/Text';
24
+ import { Area, DottedArea, GradientArea } from '../../area';
25
+ import { XAxis, YAxis } from '../../axis';
26
+ import { CartesianChart } from '../../CartesianChart';
27
+ import { useCartesianChartContext } from '../../ChartProvider';
28
+ import { PeriodSelector, PeriodSelectorActiveIndicator } from '../../PeriodSelector';
29
+ import { Point } from '../../Point';
30
+ import { Scrubber } from '../../scrubber';
31
+ import { GradientLine, Line, LineChart, ReferenceLine } from '..';
32
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
33
+ const defaultChartHeight = 200;
34
+ const formatChartDate = (timestamp, timeframe) => {
35
+ const date = new Date(timestamp);
36
+ switch (timeframe) {
37
+ case 'hour':
38
+ case '1H':
39
+ return date.toLocaleString('en-US', {
40
+ hour: 'numeric',
41
+ minute: '2-digit',
42
+ hour12: true
43
+ });
44
+ case 'day':
45
+ case '1D':
46
+ return date.toLocaleString('en-US', {
47
+ month: 'short',
48
+ day: 'numeric',
49
+ hour: 'numeric',
50
+ minute: '2-digit',
51
+ hour12: true
52
+ });
53
+ case 'week':
54
+ case 'month':
55
+ case '1W':
56
+ case '1M':
57
+ return date.toLocaleDateString('en-US', {
58
+ month: 'short',
59
+ day: 'numeric',
60
+ year: 'numeric'
61
+ });
62
+ case 'year':
63
+ case 'all':
64
+ case '1Y':
65
+ case 'All':
66
+ return date.toLocaleDateString('en-US', {
67
+ month: 'short',
68
+ year: 'numeric'
69
+ });
70
+ default:
71
+ return date.toLocaleDateString('en-US');
72
+ }
73
+ };
74
+ const calculateTrendData = (scrubberPosition, currentData, currentTimestamps, startPrice, currentPrice, activeTimeframe) => {
75
+ if (scrubberPosition !== undefined) {
76
+ // When hovering, show trend relative to START of time period (not previous point)
77
+ const hoverIndex = scrubberPosition;
78
+ const hoverPrice = currentData[hoverIndex];
79
+ const hoverPriceChange = hoverPrice - startPrice; // Fixed: relative to start price
80
+ const hoverTimestamp = currentTimestamps[hoverIndex];
81
+ return {
82
+ trendPrice: hoverPrice,
83
+ trendPreviousPrice: startPrice,
84
+ // Fixed: always use start price
85
+ trendDirection: hoverPriceChange > 0 ? 'up' : hoverPriceChange < 0 ? 'down' : 'neutral',
86
+ displayDate: formatChartDate(hoverTimestamp, activeTimeframe)
87
+ };
88
+ } else {
89
+ // When not hovering, show current trend relative to start
90
+ const latestTimestamp = currentTimestamps[currentTimestamps.length - 1];
91
+ const priceChange = currentPrice - startPrice;
92
+ return {
93
+ trendPrice: currentPrice,
94
+ trendPreviousPrice: startPrice,
95
+ trendDirection: priceChange > 0 ? 'up' : priceChange < 0 ? 'down' : 'neutral',
96
+ displayDate: formatChartDate(latestTimestamp, activeTimeframe)
97
+ };
98
+ }
99
+ };
100
+ export const BasicLineChart = () => {
101
+ const chartData = [65, 78, 45, 88, 92, 73, 69];
102
+ return /*#__PURE__*/_jsx(LineChart, {
103
+ enableScrubbing: true,
104
+ showYAxis: true,
105
+ height: defaultChartHeight,
106
+ renderPoints: () => true,
107
+ series: [{
108
+ id: 'monthly-growth',
109
+ data: chartData,
110
+ label: 'Monthly Growth',
111
+ color: '#2ca02c'
112
+ }],
113
+ yAxis: {
114
+ requestedTickCount: 2,
115
+ tickLabelFormatter: value => "$" + value,
116
+ showGrid: true
117
+ },
118
+ children: /*#__PURE__*/_jsx(Scrubber, {})
119
+ });
120
+ };
121
+ export const BasicLineChartWithPoints = () => {
122
+ const chartData = [65, 78, 45, 88, 92, 73, 69];
123
+ return /*#__PURE__*/_jsxs(LineChart, {
124
+ showYAxis: true,
125
+ height: defaultChartHeight,
126
+ renderPoints: () => true,
127
+ series: [{
128
+ id: 'monthly-growth',
129
+ data: chartData,
130
+ label: 'Monthly Growth',
131
+ color: '#2ca02c'
132
+ }],
133
+ yAxis: {
134
+ requestedTickCount: 2,
135
+ tickLabelFormatter: value => "$" + value,
136
+ showGrid: true
137
+ },
138
+ children: [/*#__PURE__*/_jsx(Point, {
139
+ dataX: 2,
140
+ dataY: 60,
141
+ fill: "purple",
142
+ label: "hello world im on a point!",
143
+ labelProps: {
144
+ verticalAlignment: 'bottom',
145
+ // why does this go in the opposite direction than what i would expect?
146
+ dy: -16
147
+ },
148
+ onPress: () => console.log('clicked'),
149
+ radius: 6,
150
+ stroke: "purple",
151
+ strokeWidth: 7
152
+ }), /*#__PURE__*/_jsx(ReferenceLine, {
153
+ dataX: 2,
154
+ label: "testing 123",
155
+ labelProps: {
156
+ color: '#10b981',
157
+ inset: 0,
158
+ verticalAlignment: 'middle'
159
+ }
160
+ }), /*#__PURE__*/_jsx(ReferenceLine, {
161
+ dataY: 60,
162
+ label: "testing 123",
163
+ labelProps: {
164
+ horizontalAlignment: 'left'
165
+ }
166
+ }), /*#__PURE__*/_jsx(Point, {
167
+ dataX: 5,
168
+ dataY: 50,
169
+ fill: "orange",
170
+ radius: 5
171
+ })]
172
+ });
173
+ };
174
+ export const AssetPrice = () => {
175
+ const pricePointsPerHour = 12;
176
+ const currentHour = 14;
177
+ const pricePointsToShow = currentHour * pricePointsPerHour;
178
+ const parsedPrices = useMemo(() => prices.slice(0, pricePointsToShow).map(price => parseFloat(price)), [pricePointsToShow]);
179
+ const [highlightedItemIndex, setHighlightedItemIndex] = useState(undefined);
180
+ const isHovering = useMemo(() => typeof highlightedItemIndex === 'number' && highlightedItemIndex < pricePointsToShow, [highlightedItemIndex, pricePointsToShow]);
181
+ const indexToTime = useCallback(index => {
182
+ const date = new Date();
183
+ date.setHours(0, 0, 0, 0);
184
+ date.setMinutes(index * 5);
185
+ return date.toLocaleTimeString('en-US', {
186
+ hour: 'numeric',
187
+ minute: '2-digit',
188
+ hour12: true
189
+ });
190
+ }, []);
191
+ const onScrubberPositionChange = useCallback(scrubberPosition => {
192
+ setHighlightedItemIndex(scrubberPosition);
193
+ }, []);
194
+ const highlightedPrice = useMemo(() => {
195
+ const price = isHovering && typeof highlightedItemIndex === 'number' ? prices[highlightedItemIndex] : prices[prices.length - 1];
196
+ return new Intl.NumberFormat('en-US', {
197
+ style: 'currency',
198
+ currency: 'USD'
199
+ }).format(parseFloat(price));
200
+ }, [highlightedItemIndex, isHovering]);
201
+
202
+ // Calculate trend information
203
+ const trendInfo = useMemo(() => {
204
+ const currentPrice = isHovering && typeof highlightedItemIndex === 'number' ? parseFloat(prices[highlightedItemIndex]) : parseFloat(prices[prices.length - 1]);
205
+ const startPrice = parseFloat(prices[0]);
206
+ const priceChange = currentPrice - startPrice;
207
+ const percentChange = priceChange / startPrice * 100;
208
+ const trendDirection = priceChange > 0 ? 'up' : priceChange < 0 ? 'down' : 'neutral';
209
+ const formattedPriceChange = new Intl.NumberFormat('en-US', {
210
+ style: 'currency',
211
+ currency: 'USD'
212
+ }).format(Math.abs(priceChange));
213
+ const formattedPercentChange = Math.abs(percentChange).toFixed(2) + "%";
214
+ return {
215
+ direction: trendDirection,
216
+ text: formattedPriceChange + " (" + formattedPercentChange + ")"
217
+ };
218
+ }, [highlightedItemIndex, isHovering]);
219
+ return /*#__PURE__*/_jsx(VStack, {
220
+ gap: 2,
221
+ children: /*#__PURE__*/_jsxs(LineChart, {
222
+ showArea: true,
223
+ height: defaultChartHeight,
224
+ inset: {
225
+ top: 4,
226
+ bottom: 8,
227
+ left: 0,
228
+ right: 0
229
+ },
230
+ onScrubberPositionChange: onScrubberPositionChange,
231
+ series: [{
232
+ id: 'price',
233
+ data: parsedPrices,
234
+ color: assets.btc.color
235
+ }],
236
+ xAxis: {
237
+ domain: {
238
+ min: 0,
239
+ max: pricePointsPerHour * 24
240
+ }
241
+ },
242
+ children: [/*#__PURE__*/_jsx(XAxis, {
243
+ tickLabelFormatter: index => indexToTime(index).slice(0, -3),
244
+ ticks: index => index % (12 * 6) === 0
245
+ }), /*#__PURE__*/_jsx(ReferenceLine, {
246
+ dataY: parsedPrices[0]
247
+ })]
248
+ })
249
+ });
250
+ };
251
+ export const LineStyles = () => {
252
+ const topChartData = [15, 28, 32, 44, 46, 36, 40, 45, 48, 38];
253
+ const upperMiddleChartData = [12, 23, 21, 29, 34, 28, 31, 38, 42, 35];
254
+ const lowerMiddleChartData = [8, 15, 14, 25, 20, 18, 22, 28, 24, 30];
255
+ const bottomChartData = [4, 8, 11, 15, 16, 14, 16, 10, 12, 14];
256
+ return /*#__PURE__*/_jsxs(CartesianChart, {
257
+ height: defaultChartHeight,
258
+ series: [{
259
+ id: 'top',
260
+ data: topChartData
261
+ }, {
262
+ id: 'upperMiddle',
263
+ data: upperMiddleChartData,
264
+ color: '#ef4444'
265
+ }, {
266
+ id: 'lowerMiddle',
267
+ data: lowerMiddleChartData,
268
+ color: '#f59e0b'
269
+ }, {
270
+ id: 'bottom',
271
+ data: bottomChartData,
272
+ color: '#800080'
273
+ }],
274
+ children: [/*#__PURE__*/_jsx(Line, {
275
+ seriesId: "top"
276
+ }), /*#__PURE__*/_jsx(Line, {
277
+ seriesId: "upperMiddle",
278
+ type: "dotted"
279
+ }), /*#__PURE__*/_jsx(Line, {
280
+ LineComponent: props => /*#__PURE__*/_jsx(GradientLine, _extends({}, props, {
281
+ endColor: "#F7931A",
282
+ startColor: "#E3D74D",
283
+ strokeWidth: 4
284
+ })),
285
+ curve: "natural",
286
+ seriesId: "lowerMiddle"
287
+ }), /*#__PURE__*/_jsx(Line, {
288
+ showArea: true,
289
+ AreaComponent: DottedArea,
290
+ curve: "step",
291
+ seriesId: "bottom"
292
+ })]
293
+ });
294
+ };
295
+ export const ChartScale = () => {
296
+ // Generate exponential growth data that benefits from log scaling
297
+ const exponentialData = [1, 2, 4, 8, 15, 30, 65, 140, 280, 580, 1200, 2400, 4800, 9500, 19000, 38000, 75000, 150000];
298
+ const scaleTypes = [{
299
+ id: 'linear',
300
+ label: 'Linear'
301
+ }, {
302
+ id: 'log',
303
+ label: 'Log'
304
+ }];
305
+ const [selectedScaleType, setSelectedScaleType] = useState(scaleTypes[0]);
306
+ return /*#__PURE__*/_jsxs(VStack, {
307
+ gap: 3,
308
+ children: [/*#__PURE__*/_jsx(VStack, {
309
+ alignItems: "flex-end",
310
+ gap: 2,
311
+ children: /*#__PURE__*/_jsxs(HStack, {
312
+ alignItems: "center",
313
+ gap: 2,
314
+ children: [/*#__PURE__*/_jsx(Text, {
315
+ font: "label1",
316
+ children: "Scale Type"
317
+ }), /*#__PURE__*/_jsx(SegmentedTabs, {
318
+ activeTab: selectedScaleType,
319
+ onChange: setSelectedScaleType,
320
+ tabs: scaleTypes
321
+ })]
322
+ })
323
+ }), /*#__PURE__*/_jsx(LineChart, {
324
+ showArea: true,
325
+ showYAxis: true,
326
+ curve: "natural",
327
+ height: defaultChartHeight,
328
+ series: [{
329
+ id: 'growth',
330
+ data: exponentialData,
331
+ color: '#10b981'
332
+ }],
333
+ yAxis: {
334
+ scaleType: selectedScaleType == null ? void 0 : selectedScaleType.id,
335
+ requestedTickCount: 5,
336
+ tickLabelFormatter: value => value.toLocaleString(),
337
+ showGrid: true,
338
+ width: 70
339
+ }
340
+ })]
341
+ });
342
+ };
343
+ export const ColorShiftChart = () => {
344
+ const theme = useTheme();
345
+ const [activeTab, setActiveTab] = useState({
346
+ id: '1H',
347
+ label: '1H'
348
+ });
349
+ const tabConversion = {
350
+ '1H': 'hour',
351
+ '1D': 'day',
352
+ '1W': 'week',
353
+ '1M': 'month',
354
+ '1Y': 'year',
355
+ All: 'all'
356
+ };
357
+ const currentPriceData = activeTab ? sparklineInteractiveData[tabConversion[activeTab.id]] : sparklineInteractiveData.hour;
358
+ const currentData = useMemo(() => [...currentPriceData.map(price => price.value)], [currentPriceData]);
359
+ const currentTimestamps = useMemo(() => [...currentPriceData.map(price => price.date.toISOString())], [currentPriceData]);
360
+ const startPrice = currentData[0];
361
+ const currentPrice = currentData[currentData.length - 1];
362
+ const priceChange = currentPrice - startPrice;
363
+
364
+ // Determine colors based on trend
365
+ const trendColor = useMemo(() => {
366
+ return priceChange >= 0 ? theme.color.fgPositive : theme.color.fgNegative;
367
+ }, [priceChange, theme.color.fgPositive, theme.color.fgNegative]);
368
+ const activeBackground = useMemo(() => {
369
+ return priceChange >= 0 ? 'bgPositiveWash' : 'bgNegativeWash';
370
+ }, [priceChange]);
371
+ const formatPrice = useCallback(price => {
372
+ return "$" + price.toLocaleString('en-US', {
373
+ minimumFractionDigits: 2,
374
+ maximumFractionDigits: 2
375
+ });
376
+ }, []);
377
+ const scrubberLabel = useCallback(index => {
378
+ const timestamp = currentTimestamps[index];
379
+ return formatChartDate(timestamp, (activeTab == null ? void 0 : activeTab.id) || '1H');
380
+ }, [activeTab == null ? void 0 : activeTab.id, currentTimestamps]);
381
+
382
+ // Custom tab component that uses the trend color for both active and inactive states
383
+ const ColorShiftTab = useMemo(() => /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) => {
384
+ let {
385
+ label
386
+ } = _ref,
387
+ props = _objectWithoutPropertiesLoose(_ref, _excluded);
388
+ return /*#__PURE__*/_jsx(SegmentedTab, _extends({
389
+ ref: ref,
390
+ activeColor: trendColor,
391
+ color: trendColor,
392
+ font: "label1",
393
+ label: label
394
+ }, props));
395
+ })), [trendColor]);
396
+ const tabs = useMemo(() => [{
397
+ id: '1H',
398
+ label: '1H'
399
+ }, {
400
+ id: '1D',
401
+ label: '1D'
402
+ }, {
403
+ id: '1W',
404
+ label: '1W'
405
+ }, {
406
+ id: '1M',
407
+ label: '1M'
408
+ }, {
409
+ id: '1Y',
410
+ label: '1Y'
411
+ }, {
412
+ id: 'All',
413
+ label: 'All'
414
+ }], []);
415
+ return /*#__PURE__*/_jsx(Box, {
416
+ style: {
417
+ marginLeft: -16,
418
+ marginRight: -16
419
+ },
420
+ children: /*#__PURE__*/_jsxs(VStack, {
421
+ gap: 3,
422
+ width: "100%",
423
+ children: [/*#__PURE__*/_jsxs(LineChart, {
424
+ enableScrubbing: true,
425
+ showArea: true,
426
+ showXAxis: true,
427
+ height: defaultChartHeight,
428
+ inset: {
429
+ left: 0,
430
+ right: 24,
431
+ bottom: 0
432
+ },
433
+ series: [{
434
+ id: 'price',
435
+ data: currentData,
436
+ color: trendColor
437
+ }],
438
+ children: [/*#__PURE__*/_jsx(Scrubber, {
439
+ idlePulse: true,
440
+ label: scrubberLabel
441
+ }), /*#__PURE__*/_jsx(ReferenceLine, {
442
+ dataY: startPrice,
443
+ label: formatPrice(startPrice),
444
+ labelProps: {
445
+ horizontalAlignment: 'right',
446
+ inset: 4,
447
+ borderRadius: 4,
448
+ dx: -8,
449
+ color: theme.color.fgInverse,
450
+ background: priceChange >= 0 ? theme.color.bgPositive : theme.color.bgNegative
451
+ },
452
+ stroke: priceChange >= 0 ? theme.color.bgPositive : theme.color.bgNegative
453
+ })]
454
+ }), /*#__PURE__*/_jsx(PeriodSelector, {
455
+ TabComponent: ColorShiftTab,
456
+ activeBackground: activeBackground,
457
+ activeTab: activeTab,
458
+ onChange: setActiveTab,
459
+ tabs: tabs
460
+ })]
461
+ })
462
+ });
463
+ };
464
+ export const PriceChart = () => {
465
+ const {
466
+ latestPrice,
467
+ formattedPrice
468
+ } = useMemo(() => {
469
+ const latestPrice = sparklineInteractiveData.hour[sparklineInteractiveData.hour.length - 1].value;
470
+ return {
471
+ latestPrice,
472
+ formattedPrice: "$" + latestPrice.toLocaleString('en-US', {
473
+ minimumFractionDigits: 2,
474
+ maximumFractionDigits: 2
475
+ })
476
+ };
477
+ }, []);
478
+ const tabs = useMemo(() => [{
479
+ id: '1H',
480
+ label: '1H'
481
+ }, {
482
+ id: '1D',
483
+ label: '1D'
484
+ }, {
485
+ id: '1W',
486
+ label: '1W'
487
+ }, {
488
+ id: '1M',
489
+ label: '1M'
490
+ }, {
491
+ id: '1Y',
492
+ label: '1Y'
493
+ }, {
494
+ id: 'All',
495
+ label: 'All'
496
+ }], []);
497
+ const [activeTab, setActiveTab] = useState(tabs[0]);
498
+ const isLive = useMemo(() => (activeTab == null ? void 0 : activeTab.id) === '1H', [activeTab]);
499
+ const activeBackground = useMemo(() => !isLive ? 'bgPrimaryWash' : 'bgNegativeWash', [isLive]);
500
+ const [isHovering, setIsHovering] = useState(false);
501
+ const tabConversion = {
502
+ '1H': 'hour',
503
+ '1D': 'day',
504
+ '1W': 'week',
505
+ '1M': 'month',
506
+ '1Y': 'year',
507
+ All: 'all'
508
+ };
509
+ const currentPriceData = activeTab ? sparklineInteractiveData[tabConversion[activeTab.id]] : sparklineInteractiveData.hour;
510
+ const currentData = useMemo(() => [...currentPriceData.map(price => price.value)], [currentPriceData]);
511
+ const currentTimestamps = useMemo(() => [...currentPriceData.map(price => price.date.toISOString())], [currentPriceData]);
512
+ const startPrice = currentData[0];
513
+ const {
514
+ lowestPriceIndices,
515
+ highestPriceIndices
516
+ } = useMemo(() => {
517
+ if (currentData.length === 0) {
518
+ return {
519
+ lowestPriceIndices: [],
520
+ highestPriceIndices: [],
521
+ minPrice: 0,
522
+ maxPrice: 0
523
+ };
524
+ }
525
+ let minPrice = currentData[0];
526
+ let maxPrice = currentData[0];
527
+
528
+ // First pass: find min and max values
529
+ for (let i = 1; i < currentData.length; i++) {
530
+ if (currentData[i] < minPrice) {
531
+ minPrice = currentData[i];
532
+ }
533
+ if (currentData[i] > maxPrice) {
534
+ maxPrice = currentData[i];
535
+ }
536
+ }
537
+
538
+ // Second pass: find all indices where min and max occur
539
+ const lowestPriceIndices = [];
540
+ const highestPriceIndices = [];
541
+ for (let i = 0; i < currentData.length; i++) {
542
+ if (currentData[i] === minPrice) {
543
+ lowestPriceIndices.push(i);
544
+ }
545
+ if (currentData[i] === maxPrice) {
546
+ highestPriceIndices.push(i);
547
+ }
548
+ }
549
+ return {
550
+ lowestPriceIndices,
551
+ highestPriceIndices,
552
+ minPrice,
553
+ maxPrice
554
+ };
555
+ }, [currentData]);
556
+ const latestPriceCoords = useMemo(() => {
557
+ if (currentData.length === 0) return {};
558
+ return {
559
+ x: currentData.length - 1,
560
+ y: currentData[currentData.length - 1]
561
+ };
562
+ }, [currentData]);
563
+ const onScrubberPositionChange = useCallback(item => {
564
+ setIsHovering(item !== undefined);
565
+ }, []);
566
+ const {
567
+ trendPrice,
568
+ trendPreviousPrice,
569
+ trendDirection
570
+ } = useMemo(() => {
571
+ return calculateTrendData(undefined, currentData, currentTimestamps, startPrice, latestPrice, (activeTab == null ? void 0 : activeTab.id) || '1H');
572
+ }, [currentData, currentTimestamps, startPrice, latestPrice, activeTab]);
573
+ const calculatedPriceChange = trendPrice - trendPreviousPrice;
574
+ const calculatedPercentChange = calculatedPriceChange / trendPreviousPrice * 100;
575
+ const formattedPriceChange = "$" + Math.abs(calculatedPriceChange).toLocaleString('en-US', {
576
+ minimumFractionDigits: 2,
577
+ maximumFractionDigits: 2
578
+ }) + " (" + Math.abs(calculatedPercentChange).toLocaleString('en-US', {
579
+ minimumFractionDigits: 2,
580
+ maximumFractionDigits: 2
581
+ }) + "%)";
582
+ const scrubberLabel = useCallback(item => {
583
+ if (item === undefined) return null;
584
+ const timestamp = currentTimestamps[item];
585
+ const price = currentData[item];
586
+ const formattedPrice = price.toLocaleString('en-US', {
587
+ minimumFractionDigits: 2,
588
+ maximumFractionDigits: 2
589
+ }) + ' USD';
590
+ const formattedDate = formatChartDate(timestamp, (activeTab == null ? void 0 : activeTab.id) || '1H');
591
+ return /*#__PURE__*/_jsxs(_Fragment, {
592
+ children: [/*#__PURE__*/_jsx("tspan", {
593
+ style: {
594
+ fontWeight: 'bold',
595
+ display: 'inline-block'
596
+ },
597
+ children: formattedPrice
598
+ }), /*#__PURE__*/_jsxs("tspan", {
599
+ style: {
600
+ display: 'inline-block'
601
+ },
602
+ children: [" ", formattedDate]
603
+ })]
604
+ });
605
+ }, [currentTimestamps, currentData, activeTab == null ? void 0 : activeTab.id]);
606
+ const formatPrice = useCallback(value => {
607
+ return "$" + value.toLocaleString('en-US', {
608
+ minimumFractionDigits: 2,
609
+ maximumFractionDigits: 2
610
+ });
611
+ }, []);
612
+ return /*#__PURE__*/_jsxs(VStack, {
613
+ gap: 3,
614
+ width: "100%",
615
+ children: [/*#__PURE__*/_jsx(LineChart, {
616
+ showArea: true,
617
+ height: defaultChartHeight,
618
+ inset: {
619
+ left: 0,
620
+ right: 3,
621
+ bottom: 3,
622
+ top: 3
623
+ },
624
+ onScrubberPositionChange: onScrubberPositionChange,
625
+ series: [{
626
+ id: 'price',
627
+ data: currentData,
628
+ color: assets.eth.color,
629
+ renderPoints: _ref2 => {
630
+ let {
631
+ dataX: index
632
+ } = _ref2;
633
+ if (highestPriceIndices.includes(index)) {
634
+ return {
635
+ opacity: 0,
636
+ label: formatPrice(currentData[index]),
637
+ labelProps: {
638
+ position: 'top',
639
+ dy: -16
640
+ }
641
+ };
642
+ }
643
+ if (lowestPriceIndices.includes(index)) {
644
+ return {
645
+ opacity: 0,
646
+ label: formatPrice(currentData[index]),
647
+ labelProps: {
648
+ position: 'bottom',
649
+ dy: 16
650
+ }
651
+ };
652
+ }
653
+ }
654
+ }],
655
+ yAxis: {
656
+ domainLimit: 'strict'
657
+ },
658
+ children: /*#__PURE__*/_jsx(Scrubber, {})
659
+ }), /*#__PURE__*/_jsx(PeriodSelector, {
660
+ activeTab: activeTab,
661
+ onChange: tab => setActiveTab(tab),
662
+ tabs: tabs
663
+ })]
664
+ });
665
+ };
666
+ export const ForecastChart = () => {
667
+ const getDataFromSparkline = startDate => {
668
+ const allData = sparklineInteractiveData.all;
669
+ if (!allData || allData.length === 0) return [];
670
+ const timelineData = allData.filter(point => point.date >= startDate);
671
+ return timelineData.map(point => ({
672
+ date: point.date,
673
+ value: point.value
674
+ }));
675
+ };
676
+ const historicalData = useMemo(() => getDataFromSparkline(new Date('2019-01-01')), []);
677
+ const annualGrowthRate = 10;
678
+ const generateForecastData = useCallback((lastDate, lastPrice, growthRate) => {
679
+ const dailyGrowthRate = Math.pow(1 + growthRate / 100, 1 / 365) - 1;
680
+ const forecastData = [];
681
+ const fiveYearsFromNow = new Date(lastDate);
682
+ fiveYearsFromNow.setFullYear(fiveYearsFromNow.getFullYear() + 5);
683
+
684
+ // Generate daily forecast points for 5 years
685
+ const currentDate = new Date(lastDate);
686
+ let currentPrice = lastPrice;
687
+ while (currentDate <= fiveYearsFromNow) {
688
+ currentPrice = currentPrice * (1 + dailyGrowthRate * 10);
689
+ forecastData.push({
690
+ date: new Date(currentDate),
691
+ value: Math.round(currentPrice)
692
+ });
693
+ currentDate.setDate(currentDate.getDate() + 10);
694
+ }
695
+ return forecastData;
696
+ }, []);
697
+ const forecastData = useMemo(() => {
698
+ if (historicalData.length === 0) return [];
699
+ const lastPoint = historicalData[historicalData.length - 1];
700
+ return generateForecastData(lastPoint.date, lastPoint.value, annualGrowthRate);
701
+ }, [generateForecastData, historicalData, annualGrowthRate]);
702
+
703
+ // Combine all data points with dates converted to timestamps for x-axis
704
+ const allDataPoints = useMemo(() => [...historicalData, ...forecastData], [historicalData, forecastData]);
705
+ const formatPrice = useCallback(price => {
706
+ return new Intl.NumberFormat('en-US', {
707
+ style: 'currency',
708
+ currency: 'USD',
709
+ minimumFractionDigits: 0,
710
+ maximumFractionDigits: 0
711
+ }).format(price);
712
+ }, []);
713
+
714
+ // Format x-axis labels to show years
715
+ const formatXAxisLabel = useCallback(timestamp => {
716
+ return new Date(timestamp).getFullYear().toString();
717
+ }, []);
718
+ return /*#__PURE__*/_jsx(LineChart, {
719
+ enableScrubbing: true,
720
+ showArea: true,
721
+ showXAxis: true,
722
+ areaType: "dotted",
723
+ height: defaultChartHeight,
724
+ inset: {
725
+ top: 4,
726
+ left: 0,
727
+ right: 0,
728
+ bottom: 0
729
+ },
730
+ series: [{
731
+ id: 'historical',
732
+ data: historicalData.map(d => d.value),
733
+ color: assets.btc.color
734
+ }, {
735
+ id: 'forecast',
736
+ data: [...historicalData.map(d => null), ...forecastData.map(d => d.value)],
737
+ color: assets.btc.color,
738
+ type: 'dotted'
739
+ }],
740
+ xAxis: {
741
+ data: allDataPoints.map(d => d.date.getTime()),
742
+ tickLabelFormatter: formatXAxisLabel,
743
+ tickInterval: 32
744
+ },
745
+ children: /*#__PURE__*/_jsx(Scrubber, {})
746
+ });
747
+ };
748
+ const PeriodSelectorExample = () => {
749
+ const tabs = [{
750
+ id: '1H',
751
+ label: '1H'
752
+ }, {
753
+ id: '1D',
754
+ label: '1D'
755
+ }, {
756
+ id: '1W',
757
+ label: '1W'
758
+ }, {
759
+ id: '1M',
760
+ label: '1M'
761
+ }, {
762
+ id: '1Y',
763
+ label: '1Y'
764
+ }, {
765
+ id: 'All',
766
+ label: 'All'
767
+ }];
768
+ const [activeTab, setActiveTab] = useState(tabs[0]);
769
+ return /*#__PURE__*/_jsx(PeriodSelector, {
770
+ activeTab: activeTab,
771
+ onChange: tab => setActiveTab(tab),
772
+ tabs: tabs
773
+ });
774
+ };
775
+ const BTCTab = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref3, ref) => {
776
+ let {
777
+ label
778
+ } = _ref3,
779
+ props = _objectWithoutPropertiesLoose(_ref3, _excluded2);
780
+ const {
781
+ activeTab
782
+ } = useTabsContext();
783
+ const isActive = (activeTab == null ? void 0 : activeTab.id) === props.id;
784
+ return /*#__PURE__*/_jsx(SegmentedTab, _extends({
785
+ ref: ref,
786
+ label: /*#__PURE__*/_jsx(TextLabel1, {
787
+ style: {
788
+ color: isActive ? assets.btc.color : undefined
789
+ },
790
+ children: label
791
+ })
792
+ }, props));
793
+ }));
794
+ const BTCActiveIndicator = /*#__PURE__*/memo(_ref4 => {
795
+ let {
796
+ style
797
+ } = _ref4,
798
+ props = _objectWithoutPropertiesLoose(_ref4, _excluded3);
799
+ return /*#__PURE__*/_jsx(PeriodSelectorActiveIndicator, _extends({}, props, {
800
+ style: [style, {
801
+ backgroundColor: assets.btc.color + "1A"
802
+ }]
803
+ }));
804
+ });
805
+ const AssetPriceDotted = () => {
806
+ const currentPrice = sparklineInteractiveData.hour[sparklineInteractiveData.hour.length - 1].value;
807
+ const tabs = useMemo(() => [{
808
+ id: 'hour',
809
+ label: '1H'
810
+ }, {
811
+ id: 'day',
812
+ label: '1D'
813
+ }, {
814
+ id: 'week',
815
+ label: '1W'
816
+ }, {
817
+ id: 'month',
818
+ label: '1M'
819
+ }, {
820
+ id: 'year',
821
+ label: '1Y'
822
+ }, {
823
+ id: 'all',
824
+ label: 'All'
825
+ }], []);
826
+ const [timePeriod, setTimePeriod] = useState(tabs[0]);
827
+ const sparklineTimePeriodData = useMemo(() => {
828
+ return sparklineInteractiveData[timePeriod.id];
829
+ }, [timePeriod]);
830
+ const sparklineTimePeriodDataValues = useMemo(() => {
831
+ return sparklineTimePeriodData.map(d => d.value);
832
+ }, [sparklineTimePeriodData]);
833
+ const sparklineTimePeriodDataTimestamps = useMemo(() => {
834
+ return sparklineTimePeriodData.map(d => d.date);
835
+ }, [sparklineTimePeriodData]);
836
+ const onPeriodChange = useCallback(period => {
837
+ setTimePeriod(period || tabs[0]);
838
+ }, [tabs, setTimePeriod]);
839
+ const formatPrice = useCallback(price => {
840
+ return new Intl.NumberFormat('en-US', {
841
+ style: 'currency',
842
+ currency: 'USD'
843
+ }).format(price);
844
+ }, []);
845
+ const formatDate = useCallback(date => {
846
+ const dayOfWeek = date.toLocaleDateString('en-US', {
847
+ weekday: 'short'
848
+ });
849
+ const monthDay = date.toLocaleDateString('en-US', {
850
+ month: 'short',
851
+ day: 'numeric'
852
+ });
853
+ const time = date.toLocaleTimeString('en-US', {
854
+ hour: 'numeric',
855
+ minute: '2-digit',
856
+ hour12: true
857
+ });
858
+ return dayOfWeek + ", " + monthDay + ", " + time;
859
+ }, []);
860
+ const scrubberLabel = useCallback(dataIndex => {
861
+ const price = new Intl.NumberFormat('en-US', {
862
+ minimumFractionDigits: 2,
863
+ maximumFractionDigits: 2
864
+ }).format(sparklineTimePeriodDataValues[dataIndex]);
865
+ const date = formatDate(sparklineTimePeriodDataTimestamps[dataIndex]);
866
+ return price + " USD " + date;
867
+ }, [sparklineTimePeriodDataValues, formatDate, sparklineTimePeriodDataTimestamps]);
868
+
869
+ // Chart overview accessibility label
870
+ const chartOverviewLabel = useMemo(() => {
871
+ if (sparklineTimePeriodData.length === 0) return '';
872
+ const firstDate = sparklineTimePeriodData[0].date;
873
+ const lastDate = sparklineTimePeriodData[sparklineTimePeriodData.length - 1].date;
874
+ const currentYear = new Date().getFullYear();
875
+ const shouldIncludeTime = timePeriod.id === 'hour' || timePeriod.id === 'day';
876
+ const dateRangeOptions = _extends({
877
+ month: 'long',
878
+ day: 'numeric',
879
+ year: firstDate.getFullYear() !== currentYear ? 'numeric' : undefined
880
+ }, shouldIncludeTime && {
881
+ hour: 'numeric',
882
+ minute: '2-digit',
883
+ hour12: true
884
+ });
885
+ const startDateStr = shouldIncludeTime ? firstDate.toLocaleString('en-US', dateRangeOptions) : firstDate.toLocaleDateString('en-US', dateRangeOptions);
886
+ const endDateStr = shouldIncludeTime ? lastDate.toLocaleString('en-US', _extends({}, dateRangeOptions, {
887
+ year: lastDate.getFullYear() !== currentYear ? 'numeric' : undefined
888
+ })) : lastDate.toLocaleDateString('en-US', _extends({}, dateRangeOptions, {
889
+ year: lastDate.getFullYear() !== currentYear ? 'numeric' : undefined
890
+ }));
891
+ return "Price chart for Bitcoin, " + startDateStr + " to " + endDateStr + ". Swipe left or right to navigate data points.";
892
+ }, [sparklineTimePeriodData, timePeriod.id]);
893
+ return /*#__PURE__*/_jsx(Box, {
894
+ accessibilityLabel: chartOverviewLabel,
895
+ accessibilityLiveRegion: "polite",
896
+ children: /*#__PURE__*/_jsxs(VStack, {
897
+ gap: 2,
898
+ children: [/*#__PURE__*/_jsx(SectionHeader, {
899
+ "aria-hidden": "true",
900
+ balance: /*#__PURE__*/_jsxs(Text, {
901
+ font: "title2",
902
+ children: [formatPrice(currentPrice), " ", sparklineTimePeriodDataValues.length]
903
+ }),
904
+ end: /*#__PURE__*/_jsx(VStack, {
905
+ justifyContent: "center",
906
+ children: /*#__PURE__*/_jsx(RemoteImage, {
907
+ shape: "circle",
908
+ size: "xl",
909
+ source: assets.btc.imageUrl
910
+ })
911
+ }),
912
+ padding: 0,
913
+ title: /*#__PURE__*/_jsx(Text, {
914
+ font: "title1",
915
+ children: "Bitcoin"
916
+ })
917
+ }), /*#__PURE__*/_jsx(LineChart, {
918
+ enableScrubbing: true,
919
+ showArea: true,
920
+ accessibilityLiveRegion: "polite",
921
+ areaType: "dotted",
922
+ height: defaultChartHeight,
923
+ series: [{
924
+ id: 'btc',
925
+ data: sparklineTimePeriodDataValues,
926
+ color: assets.btc.color
927
+ }],
928
+ children: /*#__PURE__*/_jsx(Scrubber, {
929
+ idlePulse: true,
930
+ label: scrubberLabel
931
+ })
932
+ }), /*#__PURE__*/_jsx(PeriodSelector, {
933
+ TabComponent: BTCTab,
934
+ TabsActiveIndicatorComponent: BTCActiveIndicator,
935
+ accessibilityLabel: "Select time period for chart",
936
+ activeTab: timePeriod,
937
+ onChange: onPeriodChange,
938
+ tabs: tabs
939
+ })]
940
+ })
941
+ });
942
+ };
943
+ const AssetPriceDottedNonMemoized = () => {
944
+ const [scrubIndex, setScrubIndex] = useState(undefined);
945
+ const currentPrice = sparklineInteractiveData.hour[sparklineInteractiveData.hour.length - 1].value;
946
+ const tabs = useMemo(() => [{
947
+ id: 'hour',
948
+ label: '1H'
949
+ }, {
950
+ id: 'day',
951
+ label: '1D'
952
+ }, {
953
+ id: 'week',
954
+ label: '1W'
955
+ }, {
956
+ id: 'month',
957
+ label: '1M'
958
+ }, {
959
+ id: 'year',
960
+ label: '1Y'
961
+ }, {
962
+ id: 'all',
963
+ label: 'All'
964
+ }], []);
965
+ const [timePeriod, setTimePeriod] = useState(tabs[0]);
966
+ const sparklineTimePeriodData = useMemo(() => {
967
+ return sparklineInteractiveData[timePeriod.id];
968
+ }, [timePeriod]);
969
+ const sparklineTimePeriodDataValues = useMemo(() => {
970
+ return sparklineTimePeriodData.map(d => d.value);
971
+ }, [sparklineTimePeriodData]);
972
+ const sparklineTimePeriodDataTimestamps = useMemo(() => {
973
+ return sparklineTimePeriodData.map(d => d.date);
974
+ }, [sparklineTimePeriodData]);
975
+ const onPeriodChange = useCallback(period => {
976
+ setTimePeriod(period || tabs[0]);
977
+ }, [tabs, setTimePeriod]);
978
+ const formatPrice = useCallback(price => {
979
+ return new Intl.NumberFormat('en-US', {
980
+ style: 'currency',
981
+ currency: 'USD'
982
+ }).format(price);
983
+ }, []);
984
+ const formatDate = useCallback(date => {
985
+ const dayOfWeek = date.toLocaleDateString('en-US', {
986
+ weekday: 'short'
987
+ });
988
+ const monthDay = date.toLocaleDateString('en-US', {
989
+ month: 'short',
990
+ day: 'numeric'
991
+ });
992
+ const time = date.toLocaleTimeString('en-US', {
993
+ hour: 'numeric',
994
+ minute: '2-digit',
995
+ hour12: true
996
+ });
997
+ return dayOfWeek + ", " + monthDay + ", " + time;
998
+ }, []);
999
+ const scrubberLabel = useMemo(() => {
1000
+ if (scrubIndex === undefined) return null;
1001
+ const price = new Intl.NumberFormat('en-US', {
1002
+ minimumFractionDigits: 2,
1003
+ maximumFractionDigits: 2
1004
+ }).format(sparklineTimePeriodDataValues[scrubIndex]);
1005
+ const date = formatDate(sparklineTimePeriodDataTimestamps[scrubIndex]);
1006
+ return price + " USD " + date;
1007
+ }, [scrubIndex, sparklineTimePeriodDataValues, formatDate, sparklineTimePeriodDataTimestamps]);
1008
+ return /*#__PURE__*/_jsxs(VStack, {
1009
+ gap: 2,
1010
+ children: [/*#__PURE__*/_jsx(SectionHeader, {
1011
+ balance: /*#__PURE__*/_jsxs(Text, {
1012
+ font: "title2",
1013
+ children: [formatPrice(currentPrice), " ", sparklineTimePeriodDataValues.length]
1014
+ }),
1015
+ end: /*#__PURE__*/_jsx(VStack, {
1016
+ justifyContent: "center",
1017
+ children: /*#__PURE__*/_jsx(RemoteImage, {
1018
+ shape: "circle",
1019
+ size: "xl",
1020
+ source: assets.btc.imageUrl
1021
+ })
1022
+ }),
1023
+ padding: 0,
1024
+ title: /*#__PURE__*/_jsx(Text, {
1025
+ font: "title1",
1026
+ children: "Bitcoin"
1027
+ })
1028
+ }), /*#__PURE__*/_jsx(LineChart, {
1029
+ enableScrubbing: true,
1030
+ showArea: true,
1031
+ areaType: "dotted",
1032
+ height: defaultChartHeight,
1033
+ onScrubberPositionChange: setScrubIndex,
1034
+ series: [{
1035
+ id: 'btc',
1036
+ data: sparklineTimePeriodDataValues,
1037
+ color: assets.btc.color
1038
+ }],
1039
+ children: /*#__PURE__*/_jsx(Scrubber, {
1040
+ label: scrubberLabel
1041
+ })
1042
+ }), /*#__PURE__*/_jsx(PeriodSelector, {
1043
+ TabComponent: BTCTab,
1044
+ TabsActiveIndicatorComponent: BTCActiveIndicator,
1045
+ activeTab: timePeriod,
1046
+ onChange: onPeriodChange,
1047
+ tabs: tabs
1048
+ })]
1049
+ });
1050
+ };
1051
+ const AssetPriceMultipleDotted = () => {
1052
+ const [scrubIndex, setScrubIndex] = useState(undefined);
1053
+ const currentPrice = sparklineInteractiveData.hour[sparklineInteractiveData.hour.length - 1].value;
1054
+ const tabs = useMemo(() => [{
1055
+ id: 'hour',
1056
+ label: '1H'
1057
+ }, {
1058
+ id: 'day',
1059
+ label: '1D'
1060
+ }, {
1061
+ id: 'week',
1062
+ label: '1W'
1063
+ }, {
1064
+ id: 'month',
1065
+ label: '1M'
1066
+ }, {
1067
+ id: 'year',
1068
+ label: '1Y'
1069
+ }, {
1070
+ id: 'all',
1071
+ label: 'All'
1072
+ }], []);
1073
+ const [timePeriod, setTimePeriod] = useState(tabs[0]);
1074
+ const sparklineTimePeriodData = useMemo(() => {
1075
+ return sparklineInteractiveData[timePeriod.id];
1076
+ }, [timePeriod]);
1077
+ const sparklineTimePeriodDataValues = useMemo(() => {
1078
+ return sparklineTimePeriodData.map(d => d.value);
1079
+ }, [sparklineTimePeriodData]);
1080
+ const sparklineTimePeriodDataTimestamps = useMemo(() => {
1081
+ return sparklineTimePeriodData.map(d => d.date);
1082
+ }, [sparklineTimePeriodData]);
1083
+ const onPeriodChange = useCallback(period => {
1084
+ setTimePeriod(period || tabs[0]);
1085
+ }, [tabs, setTimePeriod]);
1086
+ const formatPrice = useCallback(price => {
1087
+ return new Intl.NumberFormat('en-US', {
1088
+ style: 'currency',
1089
+ currency: 'USD'
1090
+ }).format(price);
1091
+ }, []);
1092
+ const formatDate = useCallback(date => {
1093
+ const dayOfWeek = date.toLocaleDateString('en-US', {
1094
+ weekday: 'short'
1095
+ });
1096
+ const monthDay = date.toLocaleDateString('en-US', {
1097
+ month: 'short',
1098
+ day: 'numeric'
1099
+ });
1100
+ const time = date.toLocaleTimeString('en-US', {
1101
+ hour: 'numeric',
1102
+ minute: '2-digit',
1103
+ hour12: true
1104
+ });
1105
+ return dayOfWeek + ", " + monthDay + ", " + time;
1106
+ }, []);
1107
+ const scrubberLabel = useMemo(() => {
1108
+ if (scrubIndex === undefined) return null;
1109
+ const price = new Intl.NumberFormat('en-US', {
1110
+ minimumFractionDigits: 2,
1111
+ maximumFractionDigits: 2
1112
+ }).format(sparklineTimePeriodDataValues[scrubIndex]);
1113
+ const date = formatDate(sparklineTimePeriodDataTimestamps[scrubIndex]);
1114
+ return price + " USD " + date;
1115
+ }, [scrubIndex, sparklineTimePeriodDataValues, formatDate, sparklineTimePeriodDataTimestamps]);
1116
+ return /*#__PURE__*/_jsxs(VStack, {
1117
+ gap: 2,
1118
+ children: [/*#__PURE__*/_jsx(SectionHeader, {
1119
+ balance: /*#__PURE__*/_jsxs(Text, {
1120
+ font: "title2",
1121
+ children: [formatPrice(currentPrice), " ", sparklineTimePeriodDataValues.length]
1122
+ }),
1123
+ end: /*#__PURE__*/_jsx(VStack, {
1124
+ justifyContent: "center",
1125
+ children: /*#__PURE__*/_jsx(RemoteImage, {
1126
+ shape: "circle",
1127
+ size: "xl",
1128
+ source: assets.btc.imageUrl
1129
+ })
1130
+ }),
1131
+ padding: 0,
1132
+ title: /*#__PURE__*/_jsx(Text, {
1133
+ font: "title1",
1134
+ children: "Bitcoin"
1135
+ })
1136
+ }), /*#__PURE__*/_jsx(LineChart, {
1137
+ enableScrubbing: true,
1138
+ height: defaultChartHeight,
1139
+ series: [{
1140
+ id: 'btc',
1141
+ data: sparklineTimePeriodDataValues,
1142
+ color: assets.btc.color
1143
+ }, {
1144
+ id: 'eth',
1145
+ data: sparklineTimePeriodDataValues.map(d => d * 0.75),
1146
+ color: assets.eth.color
1147
+ }, {
1148
+ id: 'xrp',
1149
+ data: sparklineTimePeriodDataValues.map(d => d * 0.5),
1150
+ color: assets.xrp.color
1151
+ }],
1152
+ children: /*#__PURE__*/_jsx(Scrubber, {})
1153
+ }), /*#__PURE__*/_jsx(PeriodSelector, {
1154
+ TabComponent: BTCTab,
1155
+ TabsActiveIndicatorComponent: BTCActiveIndicator,
1156
+ activeTab: timePeriod,
1157
+ onChange: onPeriodChange,
1158
+ tabs: tabs
1159
+ })]
1160
+ });
1161
+ };
1162
+ const GainLossChart = () => {
1163
+ const theme = useTheme();
1164
+ const gradientId = useId();
1165
+ const data = [-40, -28, -21, -5, 48, -5, -28, 2, -29, -46, 16, -30, -29, 8];
1166
+ const ChartDefs = _ref5 => {
1167
+ let {
1168
+ threshold = 0
1169
+ } = _ref5;
1170
+ const {
1171
+ getYScale
1172
+ } = useCartesianChartContext();
1173
+ // get the default y-axis scale
1174
+ const yScale = getYScale();
1175
+ if (yScale) {
1176
+ const domain = yScale.domain();
1177
+ const range = yScale.range();
1178
+ const baselinePercentage = (threshold - domain[0]) / (domain[1] - domain[0]) * 100;
1179
+ const negativeColor = "rgb(" + theme.spectrum.gray20 + ")";
1180
+ const positiveColor = theme.color.fgPositive;
1181
+ return /*#__PURE__*/_jsxs(Defs, {
1182
+ children: [/*#__PURE__*/_jsxs(LinearGradient, {
1183
+ gradientUnits: "userSpaceOnUse",
1184
+ id: gradientId + "-solid",
1185
+ x1: "0%",
1186
+ x2: "0%",
1187
+ y1: range[0],
1188
+ y2: range[1],
1189
+ children: [/*#__PURE__*/_jsx(Stop, {
1190
+ offset: "0%",
1191
+ stopColor: negativeColor
1192
+ }), /*#__PURE__*/_jsx(Stop, {
1193
+ offset: baselinePercentage + "%",
1194
+ stopColor: negativeColor
1195
+ }), /*#__PURE__*/_jsx(Stop, {
1196
+ offset: baselinePercentage + "%",
1197
+ stopColor: positiveColor
1198
+ }), /*#__PURE__*/_jsx(Stop, {
1199
+ offset: "100%",
1200
+ stopColor: positiveColor
1201
+ })]
1202
+ }), /*#__PURE__*/_jsxs(LinearGradient, {
1203
+ gradientUnits: "userSpaceOnUse",
1204
+ id: gradientId + "-gradient",
1205
+ x1: "0%",
1206
+ x2: "0%",
1207
+ y1: range[0],
1208
+ y2: range[1],
1209
+ children: [/*#__PURE__*/_jsx(Stop, {
1210
+ offset: "0%",
1211
+ stopColor: negativeColor,
1212
+ stopOpacity: 0.3
1213
+ }), /*#__PURE__*/_jsx(Stop, {
1214
+ offset: baselinePercentage + "%",
1215
+ stopColor: negativeColor,
1216
+ stopOpacity: 0
1217
+ }), /*#__PURE__*/_jsx(Stop, {
1218
+ offset: baselinePercentage + "%",
1219
+ stopColor: positiveColor,
1220
+ stopOpacity: 0
1221
+ }), /*#__PURE__*/_jsx(Stop, {
1222
+ offset: "100%",
1223
+ stopColor: positiveColor,
1224
+ stopOpacity: 0.3
1225
+ })]
1226
+ })]
1227
+ });
1228
+ }
1229
+ return null;
1230
+ };
1231
+ const tickLabelFormatter = useCallback(value => new Intl.NumberFormat('en-US', {
1232
+ style: 'currency',
1233
+ currency: 'USD',
1234
+ maximumFractionDigits: 0
1235
+ }).format(value), []);
1236
+ const solidColor = "url(#" + gradientId + "-solid)";
1237
+ return /*#__PURE__*/_jsxs(CartesianChart, {
1238
+ enableScrubbing: true,
1239
+ height: defaultChartHeight,
1240
+ inset: {
1241
+ top: 1.5,
1242
+ bottom: 1.5,
1243
+ left: 0,
1244
+ right: 0
1245
+ },
1246
+ series: [{
1247
+ id: 'prices',
1248
+ data: data,
1249
+ color: solidColor
1250
+ }],
1251
+ children: [/*#__PURE__*/_jsx(ChartDefs, {}), /*#__PURE__*/_jsx(YAxis, {
1252
+ showGrid: true,
1253
+ requestedTickCount: 2,
1254
+ tickLabelFormatter: tickLabelFormatter
1255
+ }), /*#__PURE__*/_jsx(Area, {
1256
+ curve: "monotone",
1257
+ fill: "url(#" + gradientId + "-gradient)",
1258
+ seriesId: "prices"
1259
+ }), /*#__PURE__*/_jsx(Line, {
1260
+ curve: "monotone",
1261
+ seriesId: "prices",
1262
+ stroke: solidColor,
1263
+ strokeWidth: 3
1264
+ }), /*#__PURE__*/_jsx(Scrubber, {
1265
+ hideOverlay: true
1266
+ })]
1267
+ });
1268
+ };
1269
+ const BitcoinChartWithScrubberBeacon = () => {
1270
+ const theme = useTheme();
1271
+ const prices = [...btcCandles].reverse().map(candle => parseFloat(candle.close));
1272
+ const latestPrice = prices[prices.length - 1];
1273
+ const formatPrice = price => {
1274
+ return new Intl.NumberFormat('en-US', {
1275
+ style: 'currency',
1276
+ currency: 'USD'
1277
+ }).format(price);
1278
+ };
1279
+ const formatPercentChange = price => {
1280
+ return new Intl.NumberFormat('en-US', {
1281
+ style: 'percent',
1282
+ minimumFractionDigits: 2,
1283
+ maximumFractionDigits: 2
1284
+ }).format(price);
1285
+ };
1286
+ const percentChange = (latestPrice - prices[0]) / prices[0];
1287
+ return /*#__PURE__*/_jsx(Box, {
1288
+ borderRadius: 300,
1289
+ overflow: "hidden",
1290
+ style: {
1291
+ backgroundColor: '#ED702F'
1292
+ },
1293
+ children: /*#__PURE__*/_jsxs(VStack, {
1294
+ style: {
1295
+ backgroundColor: 'rgba(0, 0, 0, 0.80)'
1296
+ },
1297
+ children: [/*#__PURE__*/_jsxs(HStack, {
1298
+ alignItems: "center",
1299
+ gap: 2,
1300
+ padding: 2,
1301
+ paddingBottom: 0,
1302
+ children: [/*#__PURE__*/_jsx(RemoteImage, {
1303
+ shape: "circle",
1304
+ size: "xxl",
1305
+ source: assets.btc.imageUrl
1306
+ }), /*#__PURE__*/_jsxs(VStack, {
1307
+ flexGrow: 1,
1308
+ gap: 0.25,
1309
+ children: [/*#__PURE__*/_jsx(Text, {
1310
+ font: "title1",
1311
+ style: {
1312
+ color: 'white'
1313
+ },
1314
+ children: "BTC"
1315
+ }), /*#__PURE__*/_jsx(Text, {
1316
+ color: "fgMuted",
1317
+ font: "label1",
1318
+ children: "Bitcoin"
1319
+ })]
1320
+ }), /*#__PURE__*/_jsxs(VStack, {
1321
+ alignItems: "flex-end",
1322
+ gap: 0.25,
1323
+ children: [/*#__PURE__*/_jsx(Text, {
1324
+ font: "title1",
1325
+ style: {
1326
+ color: 'white'
1327
+ },
1328
+ children: formatPrice(latestPrice)
1329
+ }), /*#__PURE__*/_jsxs(Text, {
1330
+ color: "fgPositive",
1331
+ font: "label1",
1332
+ children: ["+", formatPercentChange(percentChange)]
1333
+ })]
1334
+ })]
1335
+ }), /*#__PURE__*/_jsx(LineChart, {
1336
+ showArea: true,
1337
+ height: 64,
1338
+ inset: {
1339
+ left: 0,
1340
+ right: 3,
1341
+ bottom: 0,
1342
+ top: 2
1343
+ },
1344
+ series: [{
1345
+ id: 'btcPrice',
1346
+ data: prices,
1347
+ color: assets.btc.color
1348
+ }],
1349
+ width: "100%",
1350
+ children: /*#__PURE__*/_jsx(Scrubber, {})
1351
+ })]
1352
+ })
1353
+ });
1354
+ };
1355
+ const ScrubberWithImperativeHandle = () => {
1356
+ const theme = useTheme();
1357
+ const scrubberRef = useRef(null);
1358
+ return /*#__PURE__*/_jsxs(VStack, {
1359
+ gap: 2,
1360
+ children: [/*#__PURE__*/_jsx(LineChart, {
1361
+ enableScrubbing: true,
1362
+ showYAxis: true,
1363
+ height: defaultChartHeight,
1364
+ series: [{
1365
+ id: 'priceA',
1366
+ data: [2400, 1398, 9800, 3908, 4800, 3800, 4300],
1367
+ label: 'Page Views',
1368
+ color: theme.color.accentBoldBlue,
1369
+ curve: 'natural'
1370
+ }, {
1371
+ id: 'priceB',
1372
+ data: [2000, 2491, 4501, 6049, 5019, 4930, 5910],
1373
+ label: 'Unique Visitors G',
1374
+ color: theme.color.accentBoldGreen,
1375
+ curve: 'natural'
1376
+ }, {
1377
+ id: 'priceC',
1378
+ data: [1000, 4910, 2300, 5910, 3940, 2940, 1940],
1379
+ label: 'Unique Visitors P',
1380
+ color: theme.color.accentBoldPurple,
1381
+ curve: 'natural'
1382
+ }],
1383
+ yAxis: {
1384
+ domain: {
1385
+ min: 0
1386
+ },
1387
+ showGrid: true,
1388
+ tickLabelFormatter: value => value.toLocaleString()
1389
+ },
1390
+ children: /*#__PURE__*/_jsx(Scrubber, {
1391
+ ref: scrubberRef
1392
+ })
1393
+ }), /*#__PURE__*/_jsx(Button, {
1394
+ onPress: () => {
1395
+ var _scrubberRef$current;
1396
+ return (_scrubberRef$current = scrubberRef.current) == null ? void 0 : _scrubberRef$current.pulse();
1397
+ },
1398
+ children: "Pulse Beacons"
1399
+ })]
1400
+ });
1401
+ };
1402
+ const BTCPriceChart = () => {
1403
+ const tabs = [{
1404
+ id: 'hour',
1405
+ label: '1H'
1406
+ }, {
1407
+ id: 'day',
1408
+ label: '1D'
1409
+ }, {
1410
+ id: 'week',
1411
+ label: '1W'
1412
+ }, {
1413
+ id: 'month',
1414
+ label: '1M'
1415
+ }, {
1416
+ id: 'year',
1417
+ label: '1Y'
1418
+ }, {
1419
+ id: 'all',
1420
+ label: 'All'
1421
+ }];
1422
+ const [activeTab, setActiveTab] = useState(tabs[0]);
1423
+ const [highlightedItem, setHighlightedItem] = useState();
1424
+ const currentPriceData = activeTab ? sparklineInteractiveData[activeTab.id] : sparklineInteractiveData.hour;
1425
+ const currentData = useMemo(() => [...currentPriceData.map(price => price.value)], [currentPriceData]);
1426
+ const currentTimestamps = useMemo(() => [...currentPriceData.map(price => price.date.toISOString())], [currentPriceData]);
1427
+ const currentPrice = currentData[currentData.length - 1];
1428
+ const startPrice = currentData[0];
1429
+ const onScrubberPositionChange = useCallback(item => {
1430
+ setHighlightedItem(item);
1431
+ }, []);
1432
+ const displayPrice = highlightedItem !== null && highlightedItem !== undefined ? currentData[highlightedItem] : currentPrice;
1433
+ const btcAccentColor = '#F0A73C';
1434
+ const {
1435
+ displayDate
1436
+ } = useMemo(() => {
1437
+ return calculateTrendData(highlightedItem, currentData, currentTimestamps, startPrice, currentPrice, (activeTab == null ? void 0 : activeTab.id) || 'hour');
1438
+ }, [highlightedItem, currentData, currentTimestamps, startPrice, currentPrice, activeTab]);
1439
+ const formattedPrice = "$" + displayPrice.toLocaleString('en-US', {
1440
+ minimumFractionDigits: 2,
1441
+ maximumFractionDigits: 2
1442
+ });
1443
+ const AreaComponent = useMemo(() => props => /*#__PURE__*/_jsx(GradientArea, _extends({}, props, {
1444
+ peakOpacity: 0.15
1445
+ })), []);
1446
+ return /*#__PURE__*/_jsx(Box, {
1447
+ borderRadius: 300,
1448
+ overflow: "hidden",
1449
+ style: {
1450
+ backgroundColor: btcAccentColor
1451
+ },
1452
+ width: "100%",
1453
+ children: /*#__PURE__*/_jsxs(VStack, {
1454
+ gap: 3,
1455
+ width: "100%",
1456
+ children: [/*#__PURE__*/_jsxs(HStack, {
1457
+ alignItems: "flex-start",
1458
+ gap: 3,
1459
+ justifyContent: "space-between",
1460
+ padding: 4,
1461
+ children: [/*#__PURE__*/_jsxs(VStack, {
1462
+ flexGrow: 1,
1463
+ gap: 1,
1464
+ children: [/*#__PURE__*/_jsx(Text, {
1465
+ font: "title1",
1466
+ children: "Coinbase Wrapped BTC"
1467
+ }), /*#__PURE__*/_jsx(Text, {
1468
+ font: "title2",
1469
+ children: formattedPrice
1470
+ })]
1471
+ }), /*#__PURE__*/_jsx(VStack, {
1472
+ justifyContent: "center",
1473
+ children: /*#__PURE__*/_jsx(RemoteImage, {
1474
+ shape: "circle",
1475
+ size: "xxl",
1476
+ source: assets.btc.imageUrl
1477
+ })
1478
+ })]
1479
+ }), /*#__PURE__*/_jsxs(CartesianChart, {
1480
+ enableScrubbing: true,
1481
+ height: 200,
1482
+ inset: {
1483
+ bottom: 0,
1484
+ right: 3,
1485
+ left: 0,
1486
+ top: 6
1487
+ },
1488
+ onScrubberPositionChange: onScrubberPositionChange,
1489
+ series: [{
1490
+ id: 'price',
1491
+ data: currentData,
1492
+ color: 'black'
1493
+ }],
1494
+ width: "100%",
1495
+ children: [/*#__PURE__*/_jsx(Line, {
1496
+ showArea: true,
1497
+ AreaComponent: AreaComponent,
1498
+ seriesId: "price",
1499
+ strokeWidth: 3
1500
+ }), /*#__PURE__*/_jsx(Scrubber, {
1501
+ idlePulse: true,
1502
+ label: displayDate,
1503
+ labelProps: {
1504
+ color: 'black'
1505
+ },
1506
+ lineStroke: "black"
1507
+ })]
1508
+ }), /*#__PURE__*/_jsx(Box, {
1509
+ padding: 2,
1510
+ children: /*#__PURE__*/_jsx(PeriodSelector, {
1511
+ activeTab: activeTab,
1512
+ onChange: tab => setActiveTab(tab),
1513
+ tabs: tabs
1514
+ })
1515
+ })]
1516
+ })
1517
+ });
1518
+ };
1519
+ const LiveAssetPrice = () => {
1520
+ const scrubberRef = useRef(null);
1521
+ const initialData = useMemo(() => {
1522
+ return sparklineInteractiveData.hour.map(d => d.value);
1523
+ }, []);
1524
+ const [priceData, setPriceData] = useState(initialData);
1525
+ const lastDataPointTimeRef = useRef(Date.now());
1526
+ const updateCountRef = useRef(0);
1527
+ const intervalSeconds = 3600 / initialData.length;
1528
+ const maxPercentChange = Math.abs(initialData[initialData.length - 1] - initialData[0]) * 0.05;
1529
+ useEffect(() => {
1530
+ const priceUpdateInterval = setInterval(() => {
1531
+ var _scrubberRef$current2;
1532
+ setPriceData(currentData => {
1533
+ const newData = [...currentData];
1534
+ const lastPrice = newData[newData.length - 1];
1535
+ const priceChange = (Math.random() - 0.5) * maxPercentChange;
1536
+ const newPrice = Math.round((lastPrice + priceChange) * 100) / 100;
1537
+
1538
+ // Check if we should roll over to a new data point
1539
+ const currentTime = Date.now();
1540
+ const timeSinceLastPoint = (currentTime - lastDataPointTimeRef.current) / 1000;
1541
+ if (timeSinceLastPoint >= intervalSeconds) {
1542
+ // Time for a new data point - remove first, add new at end
1543
+ lastDataPointTimeRef.current = currentTime;
1544
+ newData.shift(); // Remove oldest data point
1545
+ newData.push(newPrice); // Add new data point
1546
+ updateCountRef.current = 0;
1547
+ } else {
1548
+ // Just update the last data point
1549
+ newData[newData.length - 1] = newPrice;
1550
+ updateCountRef.current++;
1551
+ }
1552
+ return newData;
1553
+ });
1554
+
1555
+ // Pulse the scrubber on each update
1556
+ (_scrubberRef$current2 = scrubberRef.current) == null || _scrubberRef$current2.pulse();
1557
+ }, 2000 + Math.random() * 1000);
1558
+ return () => clearInterval(priceUpdateInterval);
1559
+ }, [intervalSeconds, maxPercentChange]);
1560
+ return /*#__PURE__*/_jsx(LineChart, {
1561
+ enableScrubbing: true,
1562
+ showArea: true,
1563
+ height: defaultChartHeight,
1564
+ series: [{
1565
+ id: 'btc',
1566
+ data: priceData,
1567
+ color: assets.btc.color
1568
+ }],
1569
+ children: /*#__PURE__*/_jsx(Scrubber, {
1570
+ ref: scrubberRef
1571
+ })
1572
+ });
1573
+ };
1574
+ const availabilityEvents = [{
1575
+ date: new Date('2022-01-01'),
1576
+ availability: 79
1577
+ }, {
1578
+ date: new Date('2022-01-03'),
1579
+ availability: 81
1580
+ }, {
1581
+ date: new Date('2022-01-04'),
1582
+ availability: 82
1583
+ }, {
1584
+ date: new Date('2022-01-06'),
1585
+ availability: 91
1586
+ }, {
1587
+ date: new Date('2022-01-07'),
1588
+ availability: 92
1589
+ }, {
1590
+ date: new Date('2022-01-10'),
1591
+ availability: 86
1592
+ }];
1593
+
1594
+ // Generate prediction probability data for three candidates
1595
+ const generatePredictionData = () => {
1596
+ const now = new Date();
1597
+ const baseTimestamp = now.getTime();
1598
+
1599
+ // Generate data for different time periods
1600
+ const generateForPeriod = (points, intervalMs) => {
1601
+ return Array.from({
1602
+ length: points
1603
+ }, (_, i) => {
1604
+ const timestamp = new Date(baseTimestamp - (points - 1 - i) * intervalMs);
1605
+
1606
+ // Generate percentage values for three candidates that roughly sum to 100%
1607
+ const candidate1 = 45 + Math.random() * 30; // 45-75%
1608
+ const candidate2 = 15 + Math.random() * 20; // 15-35%
1609
+ const candidate3 = Math.max(0, 100 - candidate1 - candidate2 - Math.random() * 5); // remainder
1610
+
1611
+ return {
1612
+ date: timestamp,
1613
+ candidate1: Math.round(candidate1 * 10) / 10,
1614
+ candidate2: Math.round(candidate2 * 10) / 10,
1615
+ candidate3: Math.round(candidate3 * 10) / 10
1616
+ };
1617
+ });
1618
+ };
1619
+ return {
1620
+ hour: generateForPeriod(60, 60 * 1000),
1621
+ // 60 points, 1 min apart
1622
+ day: generateForPeriod(96, 15 * 60 * 1000),
1623
+ // 96 points, 15 min apart
1624
+ week: generateForPeriod(84, 2 * 60 * 60 * 1000),
1625
+ // 84 points, 2 hours apart
1626
+ month: generateForPeriod(120, 6 * 60 * 60 * 1000),
1627
+ // 120 points, 6 hours apart
1628
+ year: generateForPeriod(365, 24 * 60 * 60 * 1000),
1629
+ // 365 points, 1 day apart
1630
+ all: generateForPeriod(100, 7 * 24 * 60 * 60 * 1000) // 100 points, 1 week apart
1631
+ };
1632
+ };
1633
+ const predictionData = generatePredictionData();
1634
+ const PredictionLegend = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref6, ref) => {
1635
+ let {
1636
+ data,
1637
+ colors
1638
+ } = _ref6;
1639
+ const [selectedIndex, setSelectedIndex] = useState(data.candidate1.length - 1);
1640
+ useImperativeHandle(ref, () => ({
1641
+ updateSelectedIndex: index => {
1642
+ setSelectedIndex(index);
1643
+ }
1644
+ }));
1645
+ const candidate1Value = Math.round(data.candidate1[selectedIndex]);
1646
+ const candidate2Value = Math.round(data.candidate2[selectedIndex]);
1647
+ const candidate3Value = Math.round(data.candidate3[selectedIndex]);
1648
+ return /*#__PURE__*/_jsxs(VStack, {
1649
+ gap: 2,
1650
+ children: [/*#__PURE__*/_jsxs(HStack, {
1651
+ alignItems: "center",
1652
+ gap: 2,
1653
+ children: [/*#__PURE__*/_jsx(Box, {
1654
+ style: {
1655
+ width: 12,
1656
+ height: 12,
1657
+ borderRadius: 6,
1658
+ backgroundColor: colors.pink
1659
+ }
1660
+ }), /*#__PURE__*/_jsx(Text, {
1661
+ font: "label2",
1662
+ children: "Noah Wyle"
1663
+ }), /*#__PURE__*/_jsxs(Text, {
1664
+ font: "label1",
1665
+ children: [candidate1Value, "%"]
1666
+ })]
1667
+ }), /*#__PURE__*/_jsxs(HStack, {
1668
+ alignItems: "center",
1669
+ gap: 2,
1670
+ children: [/*#__PURE__*/_jsx(Box, {
1671
+ style: {
1672
+ width: 12,
1673
+ height: 12,
1674
+ borderRadius: 6,
1675
+ backgroundColor: colors.teal
1676
+ }
1677
+ }), /*#__PURE__*/_jsx(Text, {
1678
+ font: "label2",
1679
+ children: "Adam Scott"
1680
+ }), /*#__PURE__*/_jsxs(Text, {
1681
+ font: "label1",
1682
+ children: [candidate2Value, "%"]
1683
+ })]
1684
+ }), /*#__PURE__*/_jsxs(HStack, {
1685
+ alignItems: "center",
1686
+ gap: 2,
1687
+ children: [/*#__PURE__*/_jsx(Box, {
1688
+ style: {
1689
+ width: 12,
1690
+ height: 12,
1691
+ borderRadius: 6,
1692
+ backgroundColor: colors.green
1693
+ }
1694
+ }), /*#__PURE__*/_jsx(Text, {
1695
+ font: "label2",
1696
+ children: "Pedro Pascal"
1697
+ }), /*#__PURE__*/_jsxs(Text, {
1698
+ font: "label1",
1699
+ children: [candidate3Value, "%"]
1700
+ })]
1701
+ })]
1702
+ });
1703
+ }));
1704
+ const PredictionChart = () => {
1705
+ const theme = useTheme();
1706
+
1707
+ // Ref for the legend component
1708
+ const legendRef = useRef(null);
1709
+
1710
+ // Define colors using spectrum
1711
+ const colors = useMemo(() => ({
1712
+ pink: "rgb(" + theme.spectrum.pink50 + ")",
1713
+ teal: "rgb(" + theme.spectrum.teal50 + ")",
1714
+ green: "rgb(" + theme.spectrum.green50 + ")"
1715
+ }), [theme.spectrum]);
1716
+ const tabs = useMemo(() => [{
1717
+ id: 'hour',
1718
+ label: '1H'
1719
+ }, {
1720
+ id: 'day',
1721
+ label: '1D'
1722
+ }, {
1723
+ id: 'week',
1724
+ label: '1W'
1725
+ }, {
1726
+ id: 'month',
1727
+ label: '1M'
1728
+ }, {
1729
+ id: 'year',
1730
+ label: '1Y'
1731
+ }, {
1732
+ id: 'all',
1733
+ label: 'All'
1734
+ }], []);
1735
+ const [timePeriod, setTimePeriod] = useState(tabs[0]);
1736
+ const periodData = useMemo(() => {
1737
+ return predictionData[timePeriod.id];
1738
+ }, [timePeriod]);
1739
+ const candidate1Data = useMemo(() => periodData.map(d => d.candidate1), [periodData]);
1740
+ const candidate2Data = useMemo(() => periodData.map(d => d.candidate2), [periodData]);
1741
+ const candidate3Data = useMemo(() => periodData.map(d => d.candidate3), [periodData]);
1742
+ const timestamps = useMemo(() => periodData.map(d => d.date), [periodData]);
1743
+
1744
+ // Data object for the legend
1745
+ const legendData = useMemo(() => ({
1746
+ candidate1: candidate1Data,
1747
+ candidate2: candidate2Data,
1748
+ candidate3: candidate3Data
1749
+ }), [candidate1Data, candidate2Data, candidate3Data]);
1750
+
1751
+ // Update legend via imperative ref when scrubber position changes
1752
+ const onScrubberPositionChange = useCallback(dataIndex => {
1753
+ var _legendRef$current;
1754
+ const idx = dataIndex != null ? dataIndex : candidate1Data.length - 1;
1755
+ (_legendRef$current = legendRef.current) == null || _legendRef$current.updateSelectedIndex(idx);
1756
+ }, [candidate1Data.length]);
1757
+
1758
+ // Update legend when data length changes
1759
+ useEffect(() => {
1760
+ var _legendRef$current2;
1761
+ (_legendRef$current2 = legendRef.current) == null || _legendRef$current2.updateSelectedIndex(candidate1Data.length - 1);
1762
+ }, [candidate1Data.length]);
1763
+ const onPeriodChange = useCallback(period => {
1764
+ setTimePeriod(period || tabs[0]);
1765
+ }, [tabs]);
1766
+ const scrubberLabel = useCallback(dataIndex => {
1767
+ const date = timestamps[dataIndex];
1768
+ const currentYear = new Date().getFullYear();
1769
+ const shouldIncludeTime = timePeriod.id === 'hour' || timePeriod.id === 'day';
1770
+ const dateOptions = _extends({
1771
+ weekday: 'short',
1772
+ month: 'short',
1773
+ day: 'numeric',
1774
+ year: date.getFullYear() !== currentYear ? 'numeric' : undefined
1775
+ }, shouldIncludeTime && {
1776
+ hour: 'numeric',
1777
+ minute: '2-digit',
1778
+ hour12: true
1779
+ });
1780
+ const dateStr = shouldIncludeTime ? date.toLocaleString('en-US', dateOptions) : date.toLocaleDateString('en-US', dateOptions);
1781
+ return dateStr;
1782
+ }, [timestamps, timePeriod.id]);
1783
+ const chartOverviewLabel = useMemo(() => {
1784
+ if (periodData.length === 0) return '';
1785
+ const firstDate = periodData[0].date;
1786
+ const lastDate = periodData[periodData.length - 1].date;
1787
+ const currentYear = new Date().getFullYear();
1788
+ const shouldIncludeTime = timePeriod.id === 'hour' || timePeriod.id === 'day';
1789
+ const dateRangeOptions = _extends({
1790
+ month: 'long',
1791
+ day: 'numeric',
1792
+ year: firstDate.getFullYear() !== currentYear ? 'numeric' : undefined
1793
+ }, shouldIncludeTime && {
1794
+ hour: 'numeric',
1795
+ minute: '2-digit',
1796
+ hour12: true
1797
+ });
1798
+ const startDateStr = shouldIncludeTime ? firstDate.toLocaleString('en-US', dateRangeOptions) : firstDate.toLocaleDateString('en-US', dateRangeOptions);
1799
+ const endDateStr = shouldIncludeTime ? lastDate.toLocaleString('en-US', _extends({}, dateRangeOptions, {
1800
+ year: lastDate.getFullYear() !== currentYear ? 'numeric' : undefined
1801
+ })) : lastDate.toLocaleDateString('en-US', _extends({}, dateRangeOptions, {
1802
+ year: lastDate.getFullYear() !== currentYear ? 'numeric' : undefined
1803
+ }));
1804
+ return "Prediction chart, " + startDateStr + " to " + endDateStr + ". Swipe left or right to navigate data points.";
1805
+ }, [periodData, timePeriod.id]);
1806
+ return /*#__PURE__*/_jsx(Box, {
1807
+ accessibilityLabel: chartOverviewLabel,
1808
+ accessibilityLiveRegion: "polite",
1809
+ children: /*#__PURE__*/_jsxs(VStack, {
1810
+ gap: 4,
1811
+ children: [/*#__PURE__*/_jsx(PredictionLegend, {
1812
+ ref: legendRef,
1813
+ colors: colors,
1814
+ data: legendData
1815
+ }), /*#__PURE__*/_jsx(Box, {
1816
+ style: {
1817
+ marginLeft: -16,
1818
+ marginRight: -16
1819
+ },
1820
+ children: /*#__PURE__*/_jsx(LineChart, {
1821
+ enableScrubbing: true,
1822
+ showYAxis: true,
1823
+ accessibilityLiveRegion: "polite",
1824
+ height: defaultChartHeight,
1825
+ inset: {
1826
+ left: 0
1827
+ },
1828
+ onScrubberPositionChange: onScrubberPositionChange,
1829
+ series: [{
1830
+ id: 'candidate1',
1831
+ data: candidate1Data,
1832
+ color: colors.pink
1833
+ }, {
1834
+ id: 'candidate2',
1835
+ data: candidate2Data,
1836
+ color: colors.teal
1837
+ }, {
1838
+ id: 'candidate3',
1839
+ data: candidate3Data,
1840
+ color: colors.green
1841
+ }],
1842
+ xAxis: {
1843
+ range: _ref7 => {
1844
+ let {
1845
+ min,
1846
+ max
1847
+ } = _ref7;
1848
+ return {
1849
+ min,
1850
+ max: max - 32
1851
+ };
1852
+ }
1853
+ },
1854
+ yAxis: {
1855
+ domain: {
1856
+ min: 0,
1857
+ max: 100
1858
+ },
1859
+ tickLabelFormatter: value => value + "%",
1860
+ requestedTickCount: 5,
1861
+ showGrid: true
1862
+ },
1863
+ children: /*#__PURE__*/_jsx(Scrubber, {
1864
+ idlePulse: true,
1865
+ label: scrubberLabel
1866
+ })
1867
+ })
1868
+ }), /*#__PURE__*/_jsx(PeriodSelector, {
1869
+ accessibilityLabel: "Select time period for prediction chart",
1870
+ activeTab: timePeriod,
1871
+ onChange: onPeriodChange,
1872
+ tabs: tabs
1873
+ })]
1874
+ })
1875
+ });
1876
+ };
1877
+ const AvailabilityChart = () => {
1878
+ const theme = useTheme();
1879
+ const [scrubIndex, setScrubIndex] = useState();
1880
+ const ChartDefs = /*#__PURE__*/memo(_ref8 => {
1881
+ var _rangeBounds$min, _rangeBounds$max, _yScale, _yScale2, _yScale3, _yScale4;
1882
+ let {
1883
+ yellowThresholdPercentage = 85,
1884
+ greenThresholdPercentage = 90
1885
+ } = _ref8;
1886
+ const {
1887
+ getYScale,
1888
+ getYAxis
1889
+ } = useCartesianChartContext();
1890
+ const yScale = getYScale();
1891
+ const yAxis = getYAxis();
1892
+ if (!yScale) return null;
1893
+ const rangeBounds = yAxis == null ? void 0 : yAxis.domain;
1894
+ const rangeMin = (_rangeBounds$min = rangeBounds == null ? void 0 : rangeBounds.min) != null ? _rangeBounds$min : 0;
1895
+ const rangeMax = (_rangeBounds$max = rangeBounds == null ? void 0 : rangeBounds.max) != null ? _rangeBounds$max : 100;
1896
+
1897
+ // Calculate the Y positions in the chart coordinate system
1898
+ const yellowThresholdY = (_yScale = yScale(yellowThresholdPercentage)) != null ? _yScale : 0;
1899
+ const greenThresholdY = (_yScale2 = yScale(greenThresholdPercentage)) != null ? _yScale2 : 0;
1900
+ const minY = (_yScale3 = yScale(rangeMax)) != null ? _yScale3 : 0; // Top of chart (max value)
1901
+ const maxY = (_yScale4 = yScale(rangeMin)) != null ? _yScale4 : 0; // Bottom of chart (min value)
1902
+
1903
+ // Calculate percentages based on actual chart positions
1904
+ const yellowThreshold = (yellowThresholdY - minY) / (maxY - minY) * 100;
1905
+ const greenThreshold = (greenThresholdY - minY) / (maxY - minY) * 100;
1906
+ return /*#__PURE__*/_jsx(Defs, {
1907
+ children: /*#__PURE__*/_jsxs(LinearGradient, {
1908
+ gradientUnits: "userSpaceOnUse",
1909
+ id: "availabilityGradient",
1910
+ x1: "0%",
1911
+ x2: "0%",
1912
+ y1: minY,
1913
+ y2: maxY,
1914
+ children: [/*#__PURE__*/_jsx(Stop, {
1915
+ offset: "0%",
1916
+ stopColor: theme.color.fgPositive
1917
+ }), /*#__PURE__*/_jsx(Stop, {
1918
+ offset: greenThreshold + "%",
1919
+ stopColor: theme.color.fgPositive
1920
+ }), /*#__PURE__*/_jsx(Stop, {
1921
+ offset: greenThreshold + "%",
1922
+ stopColor: theme.color.fgWarning
1923
+ }), /*#__PURE__*/_jsx(Stop, {
1924
+ offset: yellowThreshold + "%",
1925
+ stopColor: theme.color.fgWarning
1926
+ }), /*#__PURE__*/_jsx(Stop, {
1927
+ offset: yellowThreshold + "%",
1928
+ stopColor: theme.color.fgNegative
1929
+ }), /*#__PURE__*/_jsx(Stop, {
1930
+ offset: "100%",
1931
+ stopColor: theme.color.fgNegative
1932
+ })]
1933
+ })
1934
+ });
1935
+ });
1936
+ return /*#__PURE__*/_jsxs(CartesianChart, {
1937
+ enableScrubbing: true,
1938
+ height: defaultChartHeight,
1939
+ onScrubberPositionChange: setScrubIndex,
1940
+ series: [{
1941
+ id: 'availability',
1942
+ data: availabilityEvents.map(event => event.availability),
1943
+ color: 'url(#availabilityGradient)'
1944
+ }],
1945
+ xAxis: {
1946
+ data: availabilityEvents.map(event => event.date.getTime())
1947
+ },
1948
+ yAxis: {
1949
+ domain: _ref9 => {
1950
+ let {
1951
+ min,
1952
+ max
1953
+ } = _ref9;
1954
+ return {
1955
+ min: Math.max(min - 2, 0),
1956
+ max: Math.min(max + 2, 100)
1957
+ };
1958
+ }
1959
+ },
1960
+ children: [/*#__PURE__*/_jsx(ChartDefs, {}), /*#__PURE__*/_jsx(XAxis, {
1961
+ showGrid: true,
1962
+ showLine: true,
1963
+ showTickMarks: true,
1964
+ tickLabelFormatter: value => new Date(value).toLocaleDateString()
1965
+ }), /*#__PURE__*/_jsx(YAxis, {
1966
+ showGrid: true,
1967
+ showLine: true,
1968
+ showTickMarks: true,
1969
+ position: "left",
1970
+ tickLabelFormatter: value => value + "%"
1971
+ }), /*#__PURE__*/_jsx(Line, {
1972
+ curve: "stepAfter",
1973
+ renderPoints: () => ({
1974
+ fill: theme.color.bg,
1975
+ stroke: 'url(#availabilityGradient)',
1976
+ strokeWidth: 2
1977
+ }),
1978
+ seriesId: "availability"
1979
+ }), /*#__PURE__*/_jsx(Scrubber, {
1980
+ overlayOffset: 10
1981
+ })]
1982
+ });
1983
+ };
1984
+ const sampleData = [10, 22, 29, 45, 98, 45, 22, 52, 21, 4, 68, 20, 21, 58];
1985
+ const LineChartStories = () => {
1986
+ const theme = useTheme();
1987
+ return /*#__PURE__*/_jsxs(ExampleScreen, {
1988
+ children: [/*#__PURE__*/_jsx(Example, {
1989
+ title: "Basic",
1990
+ children: /*#__PURE__*/_jsx(LineChart, {
1991
+ enableScrubbing: true,
1992
+ showArea: true,
1993
+ showYAxis: true,
1994
+ curve: "monotone",
1995
+ height: defaultChartHeight,
1996
+ series: [{
1997
+ id: 'prices',
1998
+ data: sampleData
1999
+ }],
2000
+ yAxis: {
2001
+ showGrid: true
2002
+ },
2003
+ children: /*#__PURE__*/_jsx(Scrubber, {})
2004
+ })
2005
+ }), /*#__PURE__*/_jsx(Example, {
2006
+ title: "Simple",
2007
+ children: /*#__PURE__*/_jsx(LineChart, {
2008
+ curve: "monotone",
2009
+ height: defaultChartHeight,
2010
+ series: [{
2011
+ id: 'prices',
2012
+ data: sampleData
2013
+ }]
2014
+ })
2015
+ }), /*#__PURE__*/_jsx(Example, {
2016
+ title: "Gain/Loss",
2017
+ children: /*#__PURE__*/_jsx(GainLossChart, {})
2018
+ }), /*#__PURE__*/_jsx(Example, {
2019
+ title: "BTC Price Chart",
2020
+ children: /*#__PURE__*/_jsx(BTCPriceChart, {})
2021
+ }), /*#__PURE__*/_jsx(Example, {
2022
+ title: "Price Chart",
2023
+ children: /*#__PURE__*/_jsx(PriceChart, {})
2024
+ }), /*#__PURE__*/_jsx(Example, {
2025
+ title: "Asset Price Dotted",
2026
+ children: /*#__PURE__*/_jsx(AssetPriceDotted, {})
2027
+ }), /*#__PURE__*/_jsx(Example, {
2028
+ title: "Multiple Series",
2029
+ children: /*#__PURE__*/_jsx(LineChart, {
2030
+ enableScrubbing: true,
2031
+ showXAxis: true,
2032
+ showYAxis: true,
2033
+ height: defaultChartHeight,
2034
+ series: [{
2035
+ id: 'pageViews',
2036
+ data: [2400, 1398, 9800, 3908, 4800, 3800, 4300],
2037
+ label: 'Page Views',
2038
+ color: theme.color.accentBoldBlue,
2039
+ curve: 'natural'
2040
+ }, {
2041
+ id: 'uniqueVisitors',
2042
+ data: [4000, 3000, 2000, 2780, 1890, 2390, 3490],
2043
+ label: 'Unique Visitors',
2044
+ color: theme.color.accentBoldGreen,
2045
+ curve: 'natural'
2046
+ }],
2047
+ xAxis: {
2048
+ data: ['Page A', 'Page B', 'Page C', 'Page D', 'Page E', 'Page F', 'Page G'],
2049
+ scaleType: 'band'
2050
+ },
2051
+ yAxis: {
2052
+ domain: {
2053
+ min: 0
2054
+ },
2055
+ showGrid: true,
2056
+ tickLabelFormatter: value => value.toLocaleString()
2057
+ },
2058
+ children: /*#__PURE__*/_jsx(Scrubber, {})
2059
+ })
2060
+ }), /*#__PURE__*/_jsx(Example, {
2061
+ title: "Points",
2062
+ children: /*#__PURE__*/_jsxs(CartesianChart, {
2063
+ height: defaultChartHeight,
2064
+ series: [{
2065
+ id: 'prices',
2066
+ data: [10, 22, 29, 45, 98, 45, 22, 52, 21, 4, 68, 20, 21, 58]
2067
+ }],
2068
+ children: [/*#__PURE__*/_jsx(Area, {
2069
+ curve: "monotone",
2070
+ fill: "rgb(" + theme.spectrum.blue5 + ")",
2071
+ seriesId: "prices"
2072
+ }), /*#__PURE__*/_jsx(Line, {
2073
+ curve: "monotone",
2074
+ renderPoints: _ref0 => {
2075
+ let {
2076
+ dataX
2077
+ } = _ref0,
2078
+ props = _objectWithoutPropertiesLoose(_ref0, _excluded4);
2079
+ return [4, 6, 7, 9, 10].includes(dataX) ? _extends({}, props, {
2080
+ strokeWidth: 2,
2081
+ stroke: theme.color.bg,
2082
+ radius: 5,
2083
+ onClick: () => alert('You have clicked a key market shift!')
2084
+ }) : false;
2085
+ },
2086
+ seriesId: "prices"
2087
+ })]
2088
+ })
2089
+ }), /*#__PURE__*/_jsx(Example, {
2090
+ title: "Data Formats",
2091
+ children: /*#__PURE__*/_jsx(LineChart, {
2092
+ enableScrubbing: true,
2093
+ showArea: true,
2094
+ showXAxis: true,
2095
+ showYAxis: true,
2096
+ curve: "natural",
2097
+ height: defaultChartHeight,
2098
+ renderPoints: () => true,
2099
+ series: [{
2100
+ id: 'line',
2101
+ data: [2, 5.5, 2, 8.5, 1.5, 5]
2102
+ }],
2103
+ xAxis: {
2104
+ data: [1, 2, 3, 5, 8, 10],
2105
+ showLine: true,
2106
+ showTickMarks: true,
2107
+ showGrid: true
2108
+ },
2109
+ yAxis: {
2110
+ domain: {
2111
+ min: 0
2112
+ },
2113
+ position: 'left',
2114
+ showLine: true,
2115
+ showTickMarks: true,
2116
+ showGrid: true
2117
+ },
2118
+ children: /*#__PURE__*/_jsx(Scrubber, {})
2119
+ })
2120
+ }), /*#__PURE__*/_jsx(Example, {
2121
+ title: "Bitcoin Chart with Scrubber Beacon",
2122
+ children: /*#__PURE__*/_jsx(BitcoinChartWithScrubberBeacon, {})
2123
+ }), /*#__PURE__*/_jsx(Example, {
2124
+ title: "Scrubber with Imperative Handle",
2125
+ children: /*#__PURE__*/_jsx(ScrubberWithImperativeHandle, {})
2126
+ }), /*#__PURE__*/_jsx(Example, {
2127
+ title: "Asset Price",
2128
+ children: /*#__PURE__*/_jsx(AssetPrice, {})
2129
+ }), /*#__PURE__*/_jsx(Example, {
2130
+ title: "Line Styles",
2131
+ children: /*#__PURE__*/_jsx(LineStyles, {})
2132
+ }), /*#__PURE__*/_jsx(Example, {
2133
+ title: "Chart Scale",
2134
+ children: /*#__PURE__*/_jsx(ChartScale, {})
2135
+ }), /*#__PURE__*/_jsx(Example, {
2136
+ title: "Color Shift Chart",
2137
+ children: /*#__PURE__*/_jsx(ColorShiftChart, {})
2138
+ }), /*#__PURE__*/_jsx(Example, {
2139
+ title: "Price Chart",
2140
+ children: /*#__PURE__*/_jsx(PriceChart, {})
2141
+ }), /*#__PURE__*/_jsx(Example, {
2142
+ title: "Forecast Chart",
2143
+ children: /*#__PURE__*/_jsx(ForecastChart, {})
2144
+ }), /*#__PURE__*/_jsx(Example, {
2145
+ title: "Period Selector",
2146
+ children: /*#__PURE__*/_jsx(PeriodSelectorExample, {})
2147
+ }), /*#__PURE__*/_jsx(Example, {
2148
+ title: "Live Asset Price",
2149
+ children: /*#__PURE__*/_jsx(LiveAssetPrice, {})
2150
+ }), /*#__PURE__*/_jsx(Example, {
2151
+ title: "Availability Chart",
2152
+ children: /*#__PURE__*/_jsx(AvailabilityChart, {})
2153
+ })]
2154
+ });
2155
+ };
2156
+ const AssetPriceScreen = () => {
2157
+ return /*#__PURE__*/_jsxs(ExampleScreen, {
2158
+ children: [/*#__PURE__*/_jsx(Example, {
2159
+ title: "Scrubber with Imperative Handle",
2160
+ children: /*#__PURE__*/_jsx(ScrubberWithImperativeHandle, {})
2161
+ }), /*#__PURE__*/_jsx(Example, {
2162
+ title: "Basic",
2163
+ children: /*#__PURE__*/_jsx(LineChart, {
2164
+ enableScrubbing: true,
2165
+ showArea: true,
2166
+ showYAxis: true,
2167
+ curve: "monotone",
2168
+ height: defaultChartHeight,
2169
+ series: [{
2170
+ id: 'prices',
2171
+ data: sampleData
2172
+ }],
2173
+ yAxis: {
2174
+ showGrid: true
2175
+ },
2176
+ children: /*#__PURE__*/_jsx(Scrubber, {})
2177
+ })
2178
+ }), /*#__PURE__*/_jsx(Example, {
2179
+ title: "Simple",
2180
+ children: /*#__PURE__*/_jsx(LineChart, {
2181
+ curve: "monotone",
2182
+ height: defaultChartHeight,
2183
+ series: [{
2184
+ id: 'prices',
2185
+ data: sampleData
2186
+ }]
2187
+ })
2188
+ }), /*#__PURE__*/_jsx(Example, {
2189
+ title: "Data Formats",
2190
+ children: /*#__PURE__*/_jsx(LineChart, {
2191
+ enableScrubbing: true,
2192
+ showArea: true,
2193
+ showXAxis: true,
2194
+ showYAxis: true,
2195
+ curve: "natural",
2196
+ height: defaultChartHeight,
2197
+ series: [{
2198
+ id: 'line',
2199
+ data: [2, 5.5, 2, 8.5, 1.5, 5]
2200
+ }],
2201
+ xAxis: {
2202
+ data: [1, 2, 3, 5, 8, 10],
2203
+ showLine: true,
2204
+ showTickMarks: true,
2205
+ showGrid: true
2206
+ },
2207
+ yAxis: {
2208
+ domain: {
2209
+ min: 0
2210
+ },
2211
+ position: 'left',
2212
+ showLine: true,
2213
+ showTickMarks: true,
2214
+ showGrid: true
2215
+ },
2216
+ children: /*#__PURE__*/_jsx(Scrubber, {})
2217
+ })
2218
+ }), /*#__PURE__*/_jsx(Example, {
2219
+ title: "Color Shift Chart",
2220
+ children: /*#__PURE__*/_jsx(ColorShiftChart, {})
2221
+ }), /*#__PURE__*/_jsx(Example, {
2222
+ title: "Asset Price Dotted",
2223
+ children: /*#__PURE__*/_jsx(AssetPriceDotted, {})
2224
+ }), /*#__PURE__*/_jsx(Example, {
2225
+ title: "Asset Price Multiple Dotted",
2226
+ children: /*#__PURE__*/_jsx(AssetPriceMultipleDotted, {})
2227
+ }), /*#__PURE__*/_jsx(Example, {
2228
+ title: "Asset Price Dotted (Old)",
2229
+ children: /*#__PURE__*/_jsx(AssetPriceDottedNonMemoized, {})
2230
+ }), /*#__PURE__*/_jsx(Example, {
2231
+ title: "BTC Price Chart",
2232
+ children: /*#__PURE__*/_jsx(BTCPriceChart, {})
2233
+ }), /*#__PURE__*/_jsx(Example, {
2234
+ title: "Gain/Loss",
2235
+ children: /*#__PURE__*/_jsx(GainLossChart, {})
2236
+ }), /*#__PURE__*/_jsx(Example, {
2237
+ title: "Live Asset Price",
2238
+ children: /*#__PURE__*/_jsx(LiveAssetPrice, {})
2239
+ }), /*#__PURE__*/_jsx(Example, {
2240
+ title: "Prediction Chart",
2241
+ children: /*#__PURE__*/_jsx(PredictionChart, {})
2242
+ }), /*#__PURE__*/_jsx(Example, {
2243
+ title: "Availability Chart",
2244
+ children: /*#__PURE__*/_jsx(AvailabilityChart, {})
2245
+ })]
2246
+ });
2247
+ };
2248
+ export default AssetPriceScreen;