@coinbase/cds-mobile-visualization 0.0.0 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/README.md +3 -0
  2. package/dts/index.d.ts +2 -0
  3. package/dts/index.d.ts.map +1 -0
  4. package/dts/sparkline/Counter.d.ts +3 -0
  5. package/dts/sparkline/Counter.d.ts.map +1 -0
  6. package/dts/sparkline/Sparkline.d.ts +22 -0
  7. package/dts/sparkline/Sparkline.d.ts.map +1 -0
  8. package/dts/sparkline/SparklineArea.d.ts +8 -0
  9. package/dts/sparkline/SparklineArea.d.ts.map +1 -0
  10. package/dts/sparkline/SparklineAreaPattern.d.ts +6 -0
  11. package/dts/sparkline/SparklineAreaPattern.d.ts.map +1 -0
  12. package/dts/sparkline/SparklineGradient.d.ts +12 -0
  13. package/dts/sparkline/SparklineGradient.d.ts.map +1 -0
  14. package/dts/sparkline/__figma__/Sparkline.figma.d.ts +2 -0
  15. package/dts/sparkline/__figma__/Sparkline.figma.d.ts.map +1 -0
  16. package/dts/sparkline/__stories__/Sparkline.stories.d.ts +3 -0
  17. package/dts/sparkline/__stories__/Sparkline.stories.d.ts.map +1 -0
  18. package/dts/sparkline/__stories__/SparklineGradient.stories.d.ts +3 -0
  19. package/dts/sparkline/__stories__/SparklineGradient.stories.d.ts.map +1 -0
  20. package/dts/sparkline/generateSparklineWithId.d.ts +5 -0
  21. package/dts/sparkline/generateSparklineWithId.d.ts.map +1 -0
  22. package/dts/sparkline/index.d.ts +6 -0
  23. package/dts/sparkline/index.d.ts.map +1 -0
  24. package/dts/sparkline/sparkline-interactive/SparklineAccessibleView.d.ts +18 -0
  25. package/dts/sparkline/sparkline-interactive/SparklineAccessibleView.d.ts.map +1 -0
  26. package/dts/sparkline/sparkline-interactive/SparklineInteractive.d.ts +162 -0
  27. package/dts/sparkline/sparkline-interactive/SparklineInteractive.d.ts.map +1 -0
  28. package/dts/sparkline/sparkline-interactive/SparklineInteractiveAnimatedPath.d.ts +12 -0
  29. package/dts/sparkline/sparkline-interactive/SparklineInteractiveAnimatedPath.d.ts.map +1 -0
  30. package/dts/sparkline/sparkline-interactive/SparklineInteractiveHoverDate.d.ts +17 -0
  31. package/dts/sparkline/sparkline-interactive/SparklineInteractiveHoverDate.d.ts.map +1 -0
  32. package/dts/sparkline/sparkline-interactive/SparklineInteractiveLineVertical.d.ts +8 -0
  33. package/dts/sparkline/sparkline-interactive/SparklineInteractiveLineVertical.d.ts.map +1 -0
  34. package/dts/sparkline/sparkline-interactive/SparklineInteractiveMarkerDates.d.ts +12 -0
  35. package/dts/sparkline/sparkline-interactive/SparklineInteractiveMarkerDates.d.ts.map +1 -0
  36. package/dts/sparkline/sparkline-interactive/SparklineInteractiveMinMax.d.ts +9 -0
  37. package/dts/sparkline/sparkline-interactive/SparklineInteractiveMinMax.d.ts.map +1 -0
  38. package/dts/sparkline/sparkline-interactive/SparklineInteractivePanGestureHandler.d.ts +14 -0
  39. package/dts/sparkline/sparkline-interactive/SparklineInteractivePanGestureHandler.d.ts.map +1 -0
  40. package/dts/sparkline/sparkline-interactive/SparklineInteractivePaths.d.ts +11 -0
  41. package/dts/sparkline/sparkline-interactive/SparklineInteractivePaths.d.ts.map +1 -0
  42. package/dts/sparkline/sparkline-interactive/SparklineInteractivePeriodSelector.d.ts +20 -0
  43. package/dts/sparkline/sparkline-interactive/SparklineInteractivePeriodSelector.d.ts.map +1 -0
  44. package/dts/sparkline/sparkline-interactive/SparklineInteractiveProvider.d.ts +33 -0
  45. package/dts/sparkline/sparkline-interactive/SparklineInteractiveProvider.d.ts.map +1 -0
  46. package/dts/sparkline/sparkline-interactive/SparklineInteractiveTimeseriesPaths.d.ts +23 -0
  47. package/dts/sparkline/sparkline-interactive/SparklineInteractiveTimeseriesPaths.d.ts.map +1 -0
  48. package/dts/sparkline/sparkline-interactive/__figma__/SparklineInteractive.figma.d.ts +2 -0
  49. package/dts/sparkline/sparkline-interactive/__figma__/SparklineInteractive.figma.d.ts.map +1 -0
  50. package/dts/sparkline/sparkline-interactive/__stories__/SparklineInteractive.stories.d.ts +3 -0
  51. package/dts/sparkline/sparkline-interactive/__stories__/SparklineInteractive.stories.d.ts.map +1 -0
  52. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractive.test.d.ts +2 -0
  53. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractive.test.d.ts.map +1 -0
  54. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractiveHoverDate.test.d.ts +2 -0
  55. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractiveHoverDate.test.d.ts.map +1 -0
  56. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractivePanGestureHandler.test.d.ts +2 -0
  57. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractivePanGestureHandler.test.d.ts.map +1 -0
  58. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractivePeriodSelector.test.d.ts +2 -0
  59. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractivePeriodSelector.test.d.ts.map +1 -0
  60. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractiveTimeseriesPaths.test.d.ts +2 -0
  61. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractiveTimeseriesPaths.test.d.ts.map +1 -0
  62. package/dts/sparkline/sparkline-interactive/__tests__/useMinMaxTransform.test.d.ts +2 -0
  63. package/dts/sparkline/sparkline-interactive/__tests__/useMinMaxTransform.test.d.ts.map +1 -0
  64. package/dts/sparkline/sparkline-interactive/useInterruptiblePathAnimation.d.ts +9 -0
  65. package/dts/sparkline/sparkline-interactive/useInterruptiblePathAnimation.d.ts.map +1 -0
  66. package/dts/sparkline/sparkline-interactive/useInterruptiblePathAnimation.test.disable.d.ts +2 -0
  67. package/dts/sparkline/sparkline-interactive/useInterruptiblePathAnimation.test.disable.d.ts.map +1 -0
  68. package/dts/sparkline/sparkline-interactive/useMinMaxTransform.d.ts +11 -0
  69. package/dts/sparkline/sparkline-interactive/useMinMaxTransform.d.ts.map +1 -0
  70. package/dts/sparkline/sparkline-interactive/useOpacityAnimation.d.ts +3 -0
  71. package/dts/sparkline/sparkline-interactive/useOpacityAnimation.d.ts.map +1 -0
  72. package/dts/sparkline/sparkline-interactive/useSparklineInteractiveConstants.d.ts +22 -0
  73. package/dts/sparkline/sparkline-interactive/useSparklineInteractiveConstants.d.ts.map +1 -0
  74. package/dts/sparkline/sparkline-interactive/useSparklineInteractiveLineStyles.d.ts +31 -0
  75. package/dts/sparkline/sparkline-interactive/useSparklineInteractiveLineStyles.d.ts.map +1 -0
  76. package/dts/sparkline/sparkline-interactive-header/SparklineInteractiveHeader.d.ts +110 -0
  77. package/dts/sparkline/sparkline-interactive-header/SparklineInteractiveHeader.d.ts.map +1 -0
  78. package/dts/sparkline/sparkline-interactive-header/__figma__/SparklineInteractiveHeader.figma.d.ts +2 -0
  79. package/dts/sparkline/sparkline-interactive-header/__figma__/SparklineInteractiveHeader.figma.d.ts.map +1 -0
  80. package/dts/sparkline/sparkline-interactive-header/__stories__/SparklineInteractiveHeader.stories.d.ts +4 -0
  81. package/dts/sparkline/sparkline-interactive-header/__stories__/SparklineInteractiveHeader.stories.d.ts.map +1 -0
  82. package/dts/sparkline/sparkline-interactive-header/__tests__/SparklineInteractiveHeader.test.d.ts +2 -0
  83. package/dts/sparkline/sparkline-interactive-header/__tests__/SparklineInteractiveHeader.test.d.ts.map +1 -0
  84. package/dts/sparkline/sparkline-interactive-header/__tests__/useSparklineInteractiveHeaderStyles.test.d.ts +2 -0
  85. package/dts/sparkline/sparkline-interactive-header/__tests__/useSparklineInteractiveHeaderStyles.test.d.ts.map +1 -0
  86. package/dts/sparkline/sparkline-interactive-header/useSparklineInteractiveHeaderStyles.d.ts +26 -0
  87. package/dts/sparkline/sparkline-interactive-header/useSparklineInteractiveHeaderStyles.d.ts.map +1 -0
  88. package/esm/index.js +1 -0
  89. package/esm/sparkline/Counter.js +45 -0
  90. package/esm/sparkline/Sparkline.js +51 -0
  91. package/esm/sparkline/SparklineArea.js +14 -0
  92. package/esm/sparkline/SparklineAreaPattern.js +36 -0
  93. package/esm/sparkline/SparklineGradient.js +72 -0
  94. package/esm/sparkline/__figma__/Sparkline.figma.js +22 -0
  95. package/esm/sparkline/__stories__/Sparkline.stories.js +120 -0
  96. package/esm/sparkline/__stories__/SparklineGradient.stories.js +123 -0
  97. package/esm/sparkline/generateSparklineWithId.js +6 -0
  98. package/esm/sparkline/index.js +5 -0
  99. package/esm/sparkline/sparkline-interactive/SparklineAccessibleView.js +75 -0
  100. package/esm/sparkline/sparkline-interactive/SparklineInteractive.js +303 -0
  101. package/esm/sparkline/sparkline-interactive/SparklineInteractiveAnimatedPath.js +113 -0
  102. package/esm/sparkline/sparkline-interactive/SparklineInteractiveHoverDate.js +131 -0
  103. package/esm/sparkline/sparkline-interactive/SparklineInteractiveLineVertical.js +99 -0
  104. package/esm/sparkline/sparkline-interactive/SparklineInteractiveMarkerDates.js +82 -0
  105. package/esm/sparkline/sparkline-interactive/SparklineInteractiveMinMax.js +103 -0
  106. package/esm/sparkline/sparkline-interactive/SparklineInteractivePanGestureHandler.js +104 -0
  107. package/esm/sparkline/sparkline-interactive/SparklineInteractivePaths.js +53 -0
  108. package/esm/sparkline/sparkline-interactive/SparklineInteractivePeriodSelector.js +124 -0
  109. package/esm/sparkline/sparkline-interactive/SparklineInteractiveProvider.js +80 -0
  110. package/esm/sparkline/sparkline-interactive/SparklineInteractiveTimeseriesPaths.js +109 -0
  111. package/esm/sparkline/sparkline-interactive/__figma__/SparklineInteractive.figma.js +85 -0
  112. package/esm/sparkline/sparkline-interactive/__stories__/SparklineInteractive.stories.js +474 -0
  113. package/esm/sparkline/sparkline-interactive/useInterruptiblePathAnimation.js +58 -0
  114. package/esm/sparkline/sparkline-interactive/useInterruptiblePathAnimation.test.disable.js +37 -0
  115. package/esm/sparkline/sparkline-interactive/useMinMaxTransform.js +56 -0
  116. package/esm/sparkline/sparkline-interactive/useOpacityAnimation.js +23 -0
  117. package/esm/sparkline/sparkline-interactive/useSparklineInteractiveConstants.js +47 -0
  118. package/esm/sparkline/sparkline-interactive/useSparklineInteractiveLineStyles.js +34 -0
  119. package/esm/sparkline/sparkline-interactive-header/SparklineInteractiveHeader.js +233 -0
  120. package/esm/sparkline/sparkline-interactive-header/__figma__/SparklineInteractiveHeader.figma.js +104 -0
  121. package/esm/sparkline/sparkline-interactive-header/__stories__/SparklineInteractiveHeader.stories.js +555 -0
  122. package/esm/sparkline/sparkline-interactive-header/useSparklineInteractiveHeaderStyles.js +117 -0
  123. package/package.json +64 -5
  124. package/index.js +0 -1
@@ -0,0 +1,555 @@
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 React, { useCallback, useMemo, useRef, useState } from 'react';
3
+ import { TextInput } from 'react-native';
4
+ import { sparklineInteractiveData } from '@coinbase/cds-common/internal/visualizations/SparklineInteractiveData';
5
+ import { IconButton } from '@coinbase/cds-mobile/buttons';
6
+ import { Example, ExampleScreen } from '@coinbase/cds-mobile/examples/ExampleScreen';
7
+ import { Icon } from '@coinbase/cds-mobile/icons';
8
+ import { Box, HStack } from '@coinbase/cds-mobile/layout';
9
+ import { TextTitle3 } from '@coinbase/cds-mobile/typography/TextTitle3';
10
+ import { SparklineInteractive } from '../../sparkline-interactive/SparklineInteractive';
11
+ import { SparklineInteractiveHeader } from '../SparklineInteractiveHeader';
12
+ import { useSparklineInteractiveHeaderStyles } from '../useSparklineInteractiveHeaderStyles';
13
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
14
+ const DEFAULT_PERIOD = 'day';
15
+ const periods = [{
16
+ label: '1H',
17
+ value: 'hour'
18
+ }, {
19
+ label: '1D',
20
+ value: 'day'
21
+ }, {
22
+ label: '1W',
23
+ value: 'week'
24
+ }, {
25
+ label: '1M',
26
+ value: 'month'
27
+ }, {
28
+ label: '1Y',
29
+ value: 'year'
30
+ }, {
31
+ label: 'All',
32
+ value: 'all'
33
+ }];
34
+ const periodsAlt = [{
35
+ label: '1 Std.',
36
+ value: 'hour'
37
+ }, {
38
+ label: '1 Tag',
39
+ value: 'day'
40
+ }, {
41
+ label: '1 Wo.',
42
+ value: 'week'
43
+ }, {
44
+ label: '1 Mon.',
45
+ value: 'month'
46
+ }, {
47
+ label: '1 Jahr',
48
+ value: 'year'
49
+ }, {
50
+ label: 'All',
51
+ value: 'all'
52
+ }];
53
+ const subsetOfPeriods = [{
54
+ label: '1D',
55
+ value: 'day'
56
+ }, {
57
+ label: '1M',
58
+ value: 'month'
59
+ }, {
60
+ label: '1Y',
61
+ value: 'year'
62
+ }];
63
+ function numToLocaleString(num) {
64
+ return num.toLocaleString('en-US', {
65
+ maximumFractionDigits: 2
66
+ });
67
+ }
68
+ const getFormattingConfigForPeriod = period => {
69
+ switch (period) {
70
+ case 'hour':
71
+ case 'day':
72
+ return {
73
+ hour: 'numeric',
74
+ minute: 'numeric'
75
+ };
76
+ case 'week':
77
+ case 'month':
78
+ return {
79
+ month: 'numeric',
80
+ day: 'numeric'
81
+ };
82
+ case 'year':
83
+ case 'all':
84
+ return {
85
+ month: 'numeric',
86
+ year: 'numeric'
87
+ };
88
+ }
89
+ };
90
+ const getDateHoverOptions = period => {
91
+ switch (period) {
92
+ case 'hour':
93
+ case 'day':
94
+ case 'week':
95
+ case 'month':
96
+ return {
97
+ weekday: 'short',
98
+ month: 'short',
99
+ day: 'numeric',
100
+ hour: 'numeric',
101
+ minute: 'numeric'
102
+ };
103
+ default:
104
+ return {
105
+ weekday: 'short',
106
+ year: 'numeric',
107
+ month: 'short',
108
+ day: 'numeric'
109
+ };
110
+ }
111
+ };
112
+ const generateSubHead = (point, period, sparklineInteractiveData) => {
113
+ const data = sparklineInteractiveData[period];
114
+ const firstPoint = data[0];
115
+ const increase = point.value > firstPoint.value;
116
+ return {
117
+ percent: numToLocaleString(Math.abs((point.value - firstPoint.value) / firstPoint.value) * 100) + "%",
118
+ sign: increase ? 'upwardTrend' : 'downwardTrend',
119
+ variant: increase ? 'positive' : 'negative',
120
+ accessibilityLabel: "" + (increase ? 'up' : 'down'),
121
+ priceChange: "$" + numToLocaleString(Math.abs(point.value - firstPoint.value))
122
+ };
123
+ };
124
+ const SparklineInteractiveBuild = /*#__PURE__*/React.memo(props => {
125
+ const formatDateWithConfig = useCallback((value, period) => {
126
+ const config = getFormattingConfigForPeriod(period);
127
+ return value.toLocaleString('en-US', _extends({}, config));
128
+ }, []);
129
+ const formatHoverDate = useCallback((date, period) => {
130
+ return date.toLocaleString('en-US', _extends({}, getDateHoverOptions(period)));
131
+ }, []);
132
+ const formatMinMaxLabel = useCallback(amount => {
133
+ return "$" + numToLocaleString(parseInt(amount, 10));
134
+ }, []);
135
+ return /*#__PURE__*/_jsx(SparklineInteractive, _extends({
136
+ disableScrubbing: !__DEV__
137
+ }, props, {
138
+ defaultPeriod: props.defaultPeriod || DEFAULT_PERIOD,
139
+ formatDate: formatDateWithConfig,
140
+ formatHoverDate: !props.hideHoverDate ? formatHoverDate : undefined,
141
+ formatMinMaxLabel: formatMinMaxLabel,
142
+ periods: periods,
143
+ strokeColor: props.strokeColor
144
+ }));
145
+ });
146
+ function handlePress() {
147
+ // do nothing
148
+ }
149
+ const HeaderLabel = () => {
150
+ return /*#__PURE__*/_jsxs(HStack, {
151
+ alignItems: "center",
152
+ gap: 1,
153
+ paddingBottom: 0,
154
+ children: [/*#__PURE__*/_jsx(Icon, {
155
+ active: true,
156
+ name: "wallet",
157
+ size: "s"
158
+ }), /*#__PURE__*/_jsx(TextTitle3, {
159
+ children: "CustomHeader"
160
+ })]
161
+ });
162
+ };
163
+ const SparklineInteractiveWithHeaderBuild = /*#__PURE__*/React.memo(props => {
164
+ var _props$defaultPeriod;
165
+ const {
166
+ data: sparklineData,
167
+ trailing,
168
+ labelNode,
169
+ compact
170
+ } = props;
171
+ const sparklineInteractiveData = sparklineData;
172
+ const headerRef = useRef(null);
173
+ const [currentPeriod, setCurrentPeriod] = useState((_props$defaultPeriod = props.defaultPeriod) != null ? _props$defaultPeriod : DEFAULT_PERIOD);
174
+ const data = sparklineInteractiveData[currentPeriod];
175
+ const lastPoint = data[data.length - 1];
176
+ const handleScrub = useCallback(_ref => {
177
+ var _headerRef$current;
178
+ let {
179
+ point,
180
+ period
181
+ } = _ref;
182
+ (_headerRef$current = headerRef.current) == null || _headerRef$current.update({
183
+ title: "$" + point.value.toLocaleString('en-US'),
184
+ subHead: generateSubHead(point, period, sparklineInteractiveData)
185
+ });
186
+ }, [sparklineInteractiveData]);
187
+ const handleScrubEnd = useCallback(() => {
188
+ var _headerRef$current2;
189
+ (_headerRef$current2 = headerRef.current) == null || _headerRef$current2.update({
190
+ title: "$" + numToLocaleString(lastPoint.value),
191
+ subHead: generateSubHead(lastPoint, currentPeriod, sparklineInteractiveData)
192
+ });
193
+ }, [currentPeriod, sparklineInteractiveData, lastPoint]);
194
+ const handleOnPeriodChanged = useCallback(period => {
195
+ var _headerRef$current3;
196
+ setCurrentPeriod(period);
197
+ const newData = sparklineInteractiveData[period];
198
+ const newLastPoint = newData[newData.length - 1];
199
+ (_headerRef$current3 = headerRef.current) == null || _headerRef$current3.update({
200
+ title: "$" + numToLocaleString(newLastPoint.value),
201
+ subHead: generateSubHead(newLastPoint, period, sparklineInteractiveData)
202
+ });
203
+ }, [sparklineInteractiveData]);
204
+ const header = /*#__PURE__*/_jsx(SparklineInteractiveHeader, {
205
+ ref: headerRef,
206
+ compact: compact,
207
+ defaultLabel: labelNode ? 'CustomHeader' : 'Bitcoin Price',
208
+ defaultSubHead: generateSubHead(lastPoint, currentPeriod, sparklineInteractiveData),
209
+ defaultTitle: "$" + numToLocaleString(lastPoint.value),
210
+ labelNode: labelNode,
211
+ trailing: trailing
212
+ });
213
+ return /*#__PURE__*/_jsx(SparklineInteractiveBuild, _extends({}, props, {
214
+ headerNode: header,
215
+ onPeriodChanged: handleOnPeriodChanged,
216
+ onScrub: handleScrub,
217
+ onScrubEnd: handleScrubEnd
218
+ }));
219
+ });
220
+ const SparklineInteractiveWithAltHeader = /*#__PURE__*/React.memo(props => {
221
+ var _props$defaultPeriod2;
222
+ const {
223
+ data: sparklineData,
224
+ trailing,
225
+ labelNode,
226
+ compact
227
+ } = props;
228
+ const sparklineInteractiveData = sparklineData;
229
+ const headerRef = useRef(null);
230
+ const [currentPeriod, setCurrentPeriod] = useState((_props$defaultPeriod2 = props.defaultPeriod) != null ? _props$defaultPeriod2 : DEFAULT_PERIOD);
231
+ const data = sparklineInteractiveData[currentPeriod];
232
+ const lastPoint = data[data.length - 1];
233
+ const handleScrub = useCallback(_ref2 => {
234
+ var _headerRef$current4;
235
+ let {
236
+ point,
237
+ period
238
+ } = _ref2;
239
+ (_headerRef$current4 = headerRef.current) == null || _headerRef$current4.update({
240
+ title: "$" + point.value.toLocaleString('en-US'),
241
+ subHead: generateSubHead(point, period, sparklineInteractiveData)
242
+ });
243
+ }, [sparklineInteractiveData]);
244
+ const handleScrubEnd = useCallback(() => {
245
+ var _headerRef$current5;
246
+ (_headerRef$current5 = headerRef.current) == null || _headerRef$current5.update({
247
+ title: "$" + numToLocaleString(lastPoint.value),
248
+ subHead: generateSubHead(lastPoint, currentPeriod, sparklineInteractiveData)
249
+ });
250
+ }, [currentPeriod, sparklineInteractiveData, lastPoint]);
251
+ const handleOnPeriodChanged = useCallback(period => {
252
+ var _headerRef$current6;
253
+ setCurrentPeriod(period);
254
+ const newData = sparklineInteractiveData[period];
255
+ const newLastPoint = newData[newData.length - 1];
256
+ (_headerRef$current6 = headerRef.current) == null || _headerRef$current6.update({
257
+ title: "$" + numToLocaleString(newLastPoint.value),
258
+ subHead: generateSubHead(newLastPoint, period, sparklineInteractiveData)
259
+ });
260
+ }, [sparklineInteractiveData]);
261
+ const header = /*#__PURE__*/_jsx(SparklineInteractiveHeader, {
262
+ ref: headerRef,
263
+ compact: compact,
264
+ defaultLabel: labelNode ? 'CustomHeader' : 'Bitcoin Price',
265
+ defaultSubHead: generateSubHead(lastPoint, currentPeriod, sparklineInteractiveData),
266
+ defaultTitle: "$" + numToLocaleString(lastPoint.value),
267
+ labelNode: labelNode,
268
+ trailing: trailing
269
+ });
270
+ const formatDateWithConfig = useCallback((value, period) => {
271
+ const config = getFormattingConfigForPeriod(period);
272
+ return value.toLocaleString('en-US', _extends({}, config));
273
+ }, []);
274
+ const formatHoverDate = useCallback((date, period) => {
275
+ return date.toLocaleString('en-US', _extends({}, getDateHoverOptions(period)));
276
+ }, []);
277
+ const formatMinMaxLabel = useCallback(amount => {
278
+ return "$" + numToLocaleString(parseInt(amount, 10));
279
+ }, []);
280
+ return /*#__PURE__*/_jsx(SparklineInteractive, _extends({
281
+ disableScrubbing: !__DEV__
282
+ }, props, {
283
+ defaultPeriod: props.defaultPeriod || DEFAULT_PERIOD,
284
+ formatDate: formatDateWithConfig,
285
+ formatHoverDate: !props.hideHoverDate ? formatHoverDate : undefined,
286
+ formatMinMaxLabel: formatMinMaxLabel,
287
+ headerNode: header,
288
+ onPeriodChanged: handleOnPeriodChanged,
289
+ onScrub: handleScrub,
290
+ onScrubEnd: handleScrubEnd,
291
+ periods: periodsAlt,
292
+ strokeColor: props.strokeColor
293
+ }));
294
+ });
295
+ const SparklineInteractiveWithSmallerPeriodSet = /*#__PURE__*/React.memo(props => {
296
+ var _props$defaultPeriod3;
297
+ const {
298
+ data: sparklineData,
299
+ trailing,
300
+ labelNode,
301
+ compact
302
+ } = props;
303
+ const sparklineInteractiveData = sparklineData;
304
+ const headerRef = useRef(null);
305
+ const [currentPeriod, setCurrentPeriod] = useState((_props$defaultPeriod3 = props.defaultPeriod) != null ? _props$defaultPeriod3 : DEFAULT_PERIOD);
306
+ const data = sparklineInteractiveData[currentPeriod];
307
+ const lastPoint = data[data.length - 1];
308
+ const handleScrub = useCallback(_ref3 => {
309
+ var _headerRef$current7;
310
+ let {
311
+ point,
312
+ period
313
+ } = _ref3;
314
+ (_headerRef$current7 = headerRef.current) == null || _headerRef$current7.update({
315
+ title: "$" + point.value.toLocaleString('en-US'),
316
+ subHead: generateSubHead(point, period, sparklineInteractiveData)
317
+ });
318
+ }, [sparklineInteractiveData]);
319
+ const handleScrubEnd = useCallback(() => {
320
+ var _headerRef$current8;
321
+ (_headerRef$current8 = headerRef.current) == null || _headerRef$current8.update({
322
+ title: "$" + numToLocaleString(lastPoint.value),
323
+ subHead: generateSubHead(lastPoint, currentPeriod, sparklineInteractiveData)
324
+ });
325
+ }, [currentPeriod, sparklineInteractiveData, lastPoint]);
326
+ const handleOnPeriodChanged = useCallback(period => {
327
+ var _headerRef$current9;
328
+ setCurrentPeriod(period);
329
+ const newData = sparklineInteractiveData[period];
330
+ const newLastPoint = newData[newData.length - 1];
331
+ (_headerRef$current9 = headerRef.current) == null || _headerRef$current9.update({
332
+ title: "$" + numToLocaleString(newLastPoint.value),
333
+ subHead: generateSubHead(newLastPoint, period, sparklineInteractiveData)
334
+ });
335
+ }, [sparklineInteractiveData]);
336
+ const header = /*#__PURE__*/_jsx(SparklineInteractiveHeader, {
337
+ ref: headerRef,
338
+ compact: compact,
339
+ defaultLabel: labelNode ? 'CustomHeader' : 'Bitcoin Price',
340
+ defaultSubHead: generateSubHead(lastPoint, currentPeriod, sparklineInteractiveData),
341
+ defaultTitle: "$" + numToLocaleString(lastPoint.value),
342
+ labelNode: labelNode,
343
+ trailing: trailing
344
+ });
345
+ const formatDateWithConfig = useCallback((value, period) => {
346
+ const config = getFormattingConfigForPeriod(period);
347
+ return value.toLocaleString('en-US', _extends({}, config));
348
+ }, []);
349
+ const formatHoverDate = useCallback((date, period) => {
350
+ return date.toLocaleString('en-US', _extends({}, getDateHoverOptions(period)));
351
+ }, []);
352
+ const formatMinMaxLabel = useCallback(amount => {
353
+ return "$" + numToLocaleString(parseInt(amount, 10));
354
+ }, []);
355
+ return /*#__PURE__*/_jsx(SparklineInteractive, _extends({
356
+ disableScrubbing: !__DEV__
357
+ }, props, {
358
+ defaultPeriod: props.defaultPeriod || DEFAULT_PERIOD,
359
+ formatDate: formatDateWithConfig,
360
+ formatHoverDate: !props.hideHoverDate ? formatHoverDate : undefined,
361
+ formatMinMaxLabel: formatMinMaxLabel,
362
+ headerNode: header,
363
+ onPeriodChanged: handleOnPeriodChanged,
364
+ onScrub: handleScrub,
365
+ onScrubEnd: handleScrubEnd,
366
+ periods: subsetOfPeriods,
367
+ strokeColor: props.strokeColor
368
+ }));
369
+ });
370
+ export const SparklineInteractiveHeaderWithCustomTitle = () => {
371
+ const headerRef = useRef(null);
372
+ const [currentPeriod, setCurrentPeriod] = useState('day');
373
+ const data = sparklineInteractiveData[currentPeriod];
374
+ const lastPoint = data[data.length - 1];
375
+ const titleRef = useRef(null);
376
+ const styles = useSparklineInteractiveHeaderStyles();
377
+ const handleScrub = useCallback(_ref4 => {
378
+ var _headerRef$current0, _titleRef$current;
379
+ let {
380
+ point,
381
+ period
382
+ } = _ref4;
383
+ const newTitle = "$" + point.value.toLocaleString('en-US');
384
+ (_headerRef$current0 = headerRef.current) == null || _headerRef$current0.update({
385
+ subHead: generateSubHead(point, period, sparklineInteractiveData)
386
+ });
387
+ (_titleRef$current = titleRef.current) == null || _titleRef$current.setNativeProps({
388
+ text: newTitle,
389
+ style: [styles.title(newTitle), {
390
+ color: 'green'
391
+ }]
392
+ });
393
+ }, [styles]);
394
+ const handleScrubEnd = useCallback(() => {
395
+ var _headerRef$current1, _titleRef$current2;
396
+ const newTitle = "$" + numToLocaleString(lastPoint.value);
397
+ (_headerRef$current1 = headerRef.current) == null || _headerRef$current1.update({
398
+ subHead: generateSubHead(lastPoint, currentPeriod, sparklineInteractiveData)
399
+ });
400
+ (_titleRef$current2 = titleRef.current) == null || _titleRef$current2.setNativeProps({
401
+ text: newTitle,
402
+ style: [styles.title(newTitle), {
403
+ color: 'green'
404
+ }]
405
+ });
406
+ }, [currentPeriod, lastPoint, styles]);
407
+ const handleOnPeriodChanged = useCallback(period => {
408
+ var _headerRef$current10, _titleRef$current3;
409
+ setCurrentPeriod(period);
410
+ const newData = sparklineInteractiveData[period];
411
+ const newLastPoint = newData[newData.length - 1];
412
+ const newTitle = "$" + numToLocaleString(newLastPoint.value);
413
+ (_headerRef$current10 = headerRef.current) == null || _headerRef$current10.update({
414
+ subHead: generateSubHead(newLastPoint, period, sparklineInteractiveData)
415
+ });
416
+ (_titleRef$current3 = titleRef.current) == null || _titleRef$current3.setNativeProps({
417
+ text: newTitle,
418
+ style: [styles.title(newTitle), {
419
+ color: 'green'
420
+ }]
421
+ });
422
+ }, [styles]);
423
+ const defaultTitleStyle = useMemo(() => [styles.title("$" + numToLocaleString(lastPoint.value)), {
424
+ color: 'green'
425
+ }], [lastPoint.value, styles]);
426
+ const RenderedDefaultTitle = /*#__PURE__*/_jsx(TextInput, {
427
+ ref: titleRef,
428
+ defaultValue: "$" + numToLocaleString(lastPoint.value),
429
+ editable: false,
430
+ pointerEvents: "none",
431
+ style: defaultTitleStyle,
432
+ testID: "SparklineInteractiveHeaderTitle"
433
+ });
434
+ const header = /*#__PURE__*/_jsx(SparklineInteractiveHeader, {
435
+ ref: headerRef,
436
+ defaultLabel: "Bitcoin Price",
437
+ defaultSubHead: generateSubHead(lastPoint, currentPeriod, sparklineInteractiveData),
438
+ defaultTitle: RenderedDefaultTitle
439
+ });
440
+ return /*#__PURE__*/_jsx(SparklineInteractiveBuild, {
441
+ data: sparklineInteractiveData,
442
+ headerNode: header,
443
+ onPeriodChanged: handleOnPeriodChanged,
444
+ onScrub: handleScrub,
445
+ onScrubEnd: handleScrubEnd,
446
+ strokeColor: "#F7931A"
447
+ });
448
+ };
449
+ const SparklineInteractiveHeaderScreen = () => {
450
+ const trailing = useMemo(() => {
451
+ return /*#__PURE__*/_jsxs(HStack, {
452
+ gap: 1,
453
+ children: [/*#__PURE__*/_jsx(IconButton, {
454
+ active: true,
455
+ feedback: "heavy",
456
+ name: "star",
457
+ onPress: handlePress,
458
+ variant: "secondary"
459
+ }), /*#__PURE__*/_jsx(IconButton, {
460
+ feedback: "heavy",
461
+ name: "share",
462
+ onPress: handlePress,
463
+ variant: "secondary"
464
+ })]
465
+ });
466
+ }, []);
467
+ return /*#__PURE__*/_jsxs(ExampleScreen, {
468
+ children: [/*#__PURE__*/_jsx(Example, {
469
+ padding: 0,
470
+ children: /*#__PURE__*/_jsxs(Box, {
471
+ children: [/*#__PURE__*/_jsx(TextTitle3, {
472
+ paddingX: 3,
473
+ paddingY: 3,
474
+ children: "SparklineInteractive Header Example"
475
+ }), /*#__PURE__*/_jsx(SparklineInteractiveWithHeaderBuild, {
476
+ data: sparklineInteractiveData,
477
+ strokeColor: "#F7931A"
478
+ })]
479
+ })
480
+ }), /*#__PURE__*/_jsx(Example, {
481
+ padding: 0,
482
+ children: /*#__PURE__*/_jsxs(Box, {
483
+ children: [/*#__PURE__*/_jsx(TextTitle3, {
484
+ paddingX: 3,
485
+ paddingY: 3,
486
+ children: "SparklineInteractive Header Trailing"
487
+ }), /*#__PURE__*/_jsx(SparklineInteractiveWithHeaderBuild, {
488
+ data: sparklineInteractiveData,
489
+ strokeColor: "#F7931A",
490
+ trailing: trailing
491
+ })]
492
+ })
493
+ }), /*#__PURE__*/_jsx(Example, {
494
+ padding: 0,
495
+ children: /*#__PURE__*/_jsxs(Box, {
496
+ children: [/*#__PURE__*/_jsx(TextTitle3, {
497
+ paddingX: 3,
498
+ paddingY: 3,
499
+ children: "SparklineInteractive Header Custom Label"
500
+ }), /*#__PURE__*/_jsx(SparklineInteractiveWithHeaderBuild, {
501
+ data: sparklineInteractiveData,
502
+ labelNode: /*#__PURE__*/_jsx(HeaderLabel, {}),
503
+ strokeColor: "#F7931A"
504
+ })]
505
+ })
506
+ }), /*#__PURE__*/_jsx(Example, {
507
+ padding: 0,
508
+ children: /*#__PURE__*/_jsxs(Box, {
509
+ children: [/*#__PURE__*/_jsx(TextTitle3, {
510
+ paddingX: 3,
511
+ paddingY: 3,
512
+ children: "SparklineInteractive Header Example with AltHeader"
513
+ }), /*#__PURE__*/_jsx(SparklineInteractiveWithAltHeader, {
514
+ data: sparklineInteractiveData,
515
+ strokeColor: "#F7931A"
516
+ })]
517
+ })
518
+ }), /*#__PURE__*/_jsx(Example, {
519
+ padding: 0,
520
+ children: /*#__PURE__*/_jsxs(Box, {
521
+ children: [/*#__PURE__*/_jsx(TextTitle3, {
522
+ paddingX: 3,
523
+ paddingY: 3,
524
+ children: "SparklineInteractive Header Example with Smaller Period Set"
525
+ }), /*#__PURE__*/_jsx(SparklineInteractiveWithSmallerPeriodSet, {
526
+ data: sparklineInteractiveData,
527
+ strokeColor: "#F7931A"
528
+ })]
529
+ })
530
+ }), /*#__PURE__*/_jsx(Example, {
531
+ padding: 0,
532
+ children: /*#__PURE__*/_jsxs(Box, {
533
+ children: [/*#__PURE__*/_jsx(TextTitle3, {
534
+ paddingX: 3,
535
+ paddingY: 3,
536
+ children: "SparklineInteractive Header Example with No Period Set"
537
+ }), /*#__PURE__*/_jsx(SparklineInteractiveWithHeaderBuild, {
538
+ hidePeriodSelector: true,
539
+ data: sparklineInteractiveData,
540
+ strokeColor: "#F7931A"
541
+ })]
542
+ })
543
+ }), /*#__PURE__*/_jsx(Example, {
544
+ padding: 0,
545
+ children: /*#__PURE__*/_jsxs(Box, {
546
+ children: [/*#__PURE__*/_jsx(TextTitle3, {
547
+ paddingX: 3,
548
+ paddingY: 3,
549
+ children: "SparklineInteractive Header Custom Title"
550
+ }), /*#__PURE__*/_jsx(SparklineInteractiveHeaderWithCustomTitle, {})]
551
+ })
552
+ })]
553
+ });
554
+ };
555
+ export default SparklineInteractiveHeaderScreen;
@@ -0,0 +1,117 @@
1
+ import { useCallback, useMemo } from 'react';
2
+ import { StyleSheet } from 'react-native';
3
+ import { useTheme } from '@coinbase/cds-mobile/hooks/useTheme';
4
+ import { getAdjustedFontScale } from '@coinbase/cds-mobile/utils/getAdjustedFontScale';
5
+ // The – character width is larger than the width of the + character.
6
+ // To prevent layout jank and jumping around we set a fixed width for
7
+ // this component. Because of accessible font scaling we first get the
8
+ // active font size and then calculate the character width, which for the –
9
+ // character is 0.6em.
10
+ const useSubIconWidth = () => {
11
+ const theme = useTheme();
12
+ const label1FontSize = theme.fontSize.label1;
13
+ return useCallback(color => {
14
+ const activeWidth = label1FontSize * 0.6;
15
+ // Hide if color is muted aka 0% change so icon is flushed to far left
16
+ return color === 'foregroundMuted' ? 0 : activeWidth;
17
+ }, [label1FontSize]);
18
+ };
19
+ const variantColorMap = {
20
+ positive: 'fgPositive',
21
+ negative: 'fgNegative',
22
+ foregroundMuted: 'fgMuted'
23
+ };
24
+ export const styles = StyleSheet.create({
25
+ // Inputs need to have these styles to make it appear as Text component
26
+ inputReset: {
27
+ padding: 0,
28
+ margin: 0,
29
+ backgroundColor: 'transparent',
30
+ overflow: 'visible',
31
+ lineHeight: undefined
32
+ },
33
+ fullWidth: {
34
+ width: '100%'
35
+ },
36
+ tabularNumbers: {
37
+ fontVariant: ['tabular-nums']
38
+ }
39
+ });
40
+ export function useSparklineInteractiveHeaderStyles() {
41
+ const theme = useTheme();
42
+ const typography = {
43
+ title1: {
44
+ fontSize: theme.fontSize.title1,
45
+ lineHeight: theme.lineHeight.title1,
46
+ fontFamily: theme.fontFamily.title1
47
+ },
48
+ label1: {
49
+ fontSize: theme.fontSize.label1,
50
+ lineHeight: theme.lineHeight.label1,
51
+ fontFamily: theme.fontFamily.label1
52
+ },
53
+ label2: {
54
+ fontSize: theme.fontSize.label2,
55
+ lineHeight: theme.lineHeight.label2,
56
+ fontFamily: theme.fontFamily.label2
57
+ }
58
+ };
59
+ const fontSize = {
60
+ title1: typography.title1.fontSize
61
+ };
62
+ const lineHeight = {
63
+ title1: typography.title1.lineHeight,
64
+ label1: typography.label1.lineHeight
65
+ };
66
+ const getSubIconWidth = useSubIconWidth();
67
+ return useMemo(() => {
68
+ return {
69
+ // TITLE STYLES - the large price text
70
+ title: text => {
71
+ const {
72
+ length
73
+ } = text;
74
+ // We manually decrease fontSize if length of new value
75
+ // is greater than 12 characters long
76
+ const {
77
+ fontSize: titleFontSize
78
+ } = getAdjustedFontScale({
79
+ fontSize: fontSize.title1
80
+ }, length, 12);
81
+ return [typography.title1, styles.tabularNumbers, styles.inputReset, styles.fullWidth, {
82
+ fontSize: titleFontSize,
83
+ color: theme.color.fg,
84
+ height: lineHeight.title1
85
+ }];
86
+ },
87
+ // LABEL STYLES - the small text above price
88
+ label: [typography.label1, styles.inputReset, styles.fullWidth, {
89
+ height: lineHeight.label1,
90
+ color: theme.color.fgMuted
91
+ }],
92
+ // SUBHEAD ICON STYLES - the + or - after price and in front of percent change)
93
+ subHeadIcon: color => [typography.label1, styles.inputReset, {
94
+ color: theme.color[variantColorMap[color]],
95
+ width: getSubIconWidth(color),
96
+ marginRight: theme.space[0.5] / 2,
97
+ textAlign: 'left'
98
+ }],
99
+ // SUBHEAD STYLES - the percent change text
100
+ subHead: function (color, useFullWidth) {
101
+ if (useFullWidth === void 0) {
102
+ useFullWidth = true;
103
+ }
104
+ return [typography.label1, styles.tabularNumbers, ...(useFullWidth ? [styles.fullWidth] : [{
105
+ width: 'auto'
106
+ }]), styles.inputReset, {
107
+ color: theme.color[variantColorMap[color]]
108
+ }];
109
+ },
110
+ subHeadAccessory: () => [typography.label2, styles.inputReset, {
111
+ color: theme.color.fgMuted,
112
+ marginLeft: theme.space[0.5],
113
+ textAlign: 'left'
114
+ }]
115
+ };
116
+ }, [typography.label1, typography.title1, typography.label2, lineHeight.label1, lineHeight.title1, theme.color, theme.space, fontSize.title1, getSubIconWidth]);
117
+ }