@coinbase/cds-web-visualization 0.0.0 → 3.3.2

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 (95) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +3 -0
  3. package/dts/index.d.ts +2 -0
  4. package/dts/index.d.ts.map +1 -0
  5. package/dts/sparkline/Counter.d.ts +8 -0
  6. package/dts/sparkline/Counter.d.ts.map +1 -0
  7. package/dts/sparkline/Sparkline.d.ts +32 -0
  8. package/dts/sparkline/Sparkline.d.ts.map +1 -0
  9. package/dts/sparkline/SparklineArea.d.ts +11 -0
  10. package/dts/sparkline/SparklineArea.d.ts.map +1 -0
  11. package/dts/sparkline/SparklineAreaPattern.d.ts +9 -0
  12. package/dts/sparkline/SparklineAreaPattern.d.ts.map +1 -0
  13. package/dts/sparkline/SparklineGradient.d.ts +18 -0
  14. package/dts/sparkline/SparklineGradient.d.ts.map +1 -0
  15. package/dts/sparkline/SparklinePath.d.ts +12 -0
  16. package/dts/sparkline/SparklinePath.d.ts.map +1 -0
  17. package/dts/sparkline/__figma__/Sparkline.figma.d.ts +2 -0
  18. package/dts/sparkline/__figma__/Sparkline.figma.d.ts.map +1 -0
  19. package/dts/sparkline/generateSparklineWithId.d.ts +10 -0
  20. package/dts/sparkline/generateSparklineWithId.d.ts.map +1 -0
  21. package/dts/sparkline/index.d.ts +6 -0
  22. package/dts/sparkline/index.d.ts.map +1 -0
  23. package/dts/sparkline/sparkline-interactive/InnerSparklineInteractiveProvider.d.ts +13 -0
  24. package/dts/sparkline/sparkline-interactive/InnerSparklineInteractiveProvider.d.ts.map +1 -0
  25. package/dts/sparkline/sparkline-interactive/SparklineInteractive.d.ts +190 -0
  26. package/dts/sparkline/sparkline-interactive/SparklineInteractive.d.ts.map +1 -0
  27. package/dts/sparkline/sparkline-interactive/SparklineInteractiveAnimatedPath.d.ts +23 -0
  28. package/dts/sparkline/sparkline-interactive/SparklineInteractiveAnimatedPath.d.ts.map +1 -0
  29. package/dts/sparkline/sparkline-interactive/SparklineInteractiveHoverDate.d.ts +5 -0
  30. package/dts/sparkline/sparkline-interactive/SparklineInteractiveHoverDate.d.ts.map +1 -0
  31. package/dts/sparkline/sparkline-interactive/SparklineInteractiveHoverPrice.d.ts +5 -0
  32. package/dts/sparkline/sparkline-interactive/SparklineInteractiveHoverPrice.d.ts.map +1 -0
  33. package/dts/sparkline/sparkline-interactive/SparklineInteractiveLineVertical.d.ts +8 -0
  34. package/dts/sparkline/sparkline-interactive/SparklineInteractiveLineVertical.d.ts.map +1 -0
  35. package/dts/sparkline/sparkline-interactive/SparklineInteractiveMarkerDates.d.ts +17 -0
  36. package/dts/sparkline/sparkline-interactive/SparklineInteractiveMarkerDates.d.ts.map +1 -0
  37. package/dts/sparkline/sparkline-interactive/SparklineInteractivePaths.d.ts +24 -0
  38. package/dts/sparkline/sparkline-interactive/SparklineInteractivePaths.d.ts.map +1 -0
  39. package/dts/sparkline/sparkline-interactive/SparklineInteractivePeriodSelector.d.ts +25 -0
  40. package/dts/sparkline/sparkline-interactive/SparklineInteractivePeriodSelector.d.ts.map +1 -0
  41. package/dts/sparkline/sparkline-interactive/SparklineInteractiveProvider.d.ts +25 -0
  42. package/dts/sparkline/sparkline-interactive/SparklineInteractiveProvider.d.ts.map +1 -0
  43. package/dts/sparkline/sparkline-interactive/SparklineInteractiveScrubHandler.d.ts +30 -0
  44. package/dts/sparkline/sparkline-interactive/SparklineInteractiveScrubHandler.d.ts.map +1 -0
  45. package/dts/sparkline/sparkline-interactive/SparklineInteractiveScrubProvider.d.ts +18 -0
  46. package/dts/sparkline/sparkline-interactive/SparklineInteractiveScrubProvider.d.ts.map +1 -0
  47. package/dts/sparkline/sparkline-interactive/SparklineInteractiveTimeseriesPaths.d.ts +31 -0
  48. package/dts/sparkline/sparkline-interactive/SparklineInteractiveTimeseriesPaths.d.ts.map +1 -0
  49. package/dts/sparkline/sparkline-interactive/__figma__/SparklineInteractive.figma.d.ts +2 -0
  50. package/dts/sparkline/sparkline-interactive/__figma__/SparklineInteractive.figma.d.ts.map +1 -0
  51. package/dts/sparkline/sparkline-interactive/fade.d.ts +3 -0
  52. package/dts/sparkline/sparkline-interactive/fade.d.ts.map +1 -0
  53. package/dts/sparkline/sparkline-interactive/useSparklineInteractiveConstants.d.ts +13 -0
  54. package/dts/sparkline/sparkline-interactive/useSparklineInteractiveConstants.d.ts.map +1 -0
  55. package/dts/sparkline/sparkline-interactive-header/SparklineInteractiveHeader.d.ts +112 -0
  56. package/dts/sparkline/sparkline-interactive-header/SparklineInteractiveHeader.d.ts.map +1 -0
  57. package/dts/sparkline/sparkline-interactive-header/__figma__/SparklineInteractiveHeader.figma.d.ts +2 -0
  58. package/dts/sparkline/sparkline-interactive-header/__figma__/SparklineInteractiveHeader.figma.d.ts.map +1 -0
  59. package/esm/index.js +1 -0
  60. package/esm/sparkline/Counter.css +3 -0
  61. package/esm/sparkline/Counter.js +35 -0
  62. package/esm/sparkline/Sparkline.js +50 -0
  63. package/esm/sparkline/SparklineArea.js +13 -0
  64. package/esm/sparkline/SparklineAreaPattern.js +35 -0
  65. package/esm/sparkline/SparklineGradient.js +72 -0
  66. package/esm/sparkline/SparklinePath.js +19 -0
  67. package/esm/sparkline/__figma__/Sparkline.figma.js +24 -0
  68. package/esm/sparkline/generateSparklineWithId.js +6 -0
  69. package/esm/sparkline/index.js +5 -0
  70. package/esm/sparkline/sparkline-interactive/InnerSparklineInteractiveProvider.js +21 -0
  71. package/esm/sparkline/sparkline-interactive/SparklineInteractive.js +313 -0
  72. package/esm/sparkline/sparkline-interactive/SparklineInteractiveAnimatedPath.js +105 -0
  73. package/esm/sparkline/sparkline-interactive/SparklineInteractiveHoverDate.css +2 -0
  74. package/esm/sparkline/sparkline-interactive/SparklineInteractiveHoverDate.js +26 -0
  75. package/esm/sparkline/sparkline-interactive/SparklineInteractiveHoverPrice.css +2 -0
  76. package/esm/sparkline/sparkline-interactive/SparklineInteractiveHoverPrice.js +24 -0
  77. package/esm/sparkline/sparkline-interactive/SparklineInteractiveLineVertical.css +4 -0
  78. package/esm/sparkline/sparkline-interactive/SparklineInteractiveLineVertical.js +65 -0
  79. package/esm/sparkline/sparkline-interactive/SparklineInteractiveMarkerDates.css +1 -0
  80. package/esm/sparkline/sparkline-interactive/SparklineInteractiveMarkerDates.js +84 -0
  81. package/esm/sparkline/sparkline-interactive/SparklineInteractivePaths.js +52 -0
  82. package/esm/sparkline/sparkline-interactive/SparklineInteractivePeriodSelector.js +70 -0
  83. package/esm/sparkline/sparkline-interactive/SparklineInteractiveProvider.js +45 -0
  84. package/esm/sparkline/sparkline-interactive/SparklineInteractiveScrubHandler.css +5 -0
  85. package/esm/sparkline/sparkline-interactive/SparklineInteractiveScrubHandler.js +199 -0
  86. package/esm/sparkline/sparkline-interactive/SparklineInteractiveScrubProvider.js +39 -0
  87. package/esm/sparkline/sparkline-interactive/SparklineInteractiveTimeseriesPaths.js +92 -0
  88. package/esm/sparkline/sparkline-interactive/__figma__/SparklineInteractive.figma.js +89 -0
  89. package/esm/sparkline/sparkline-interactive/fade.css +2 -0
  90. package/esm/sparkline/sparkline-interactive/fade.js +14 -0
  91. package/esm/sparkline/sparkline-interactive/useSparklineInteractiveConstants.js +28 -0
  92. package/esm/sparkline/sparkline-interactive-header/SparklineInteractiveHeader.js +225 -0
  93. package/esm/sparkline/sparkline-interactive-header/__figma__/SparklineInteractiveHeader.figma.js +108 -0
  94. package/package.json +64 -6
  95. package/index.js +0 -1
@@ -0,0 +1,313 @@
1
+ const _excluded = ["compact"];
2
+ function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
3
+ function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
4
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
5
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
6
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
7
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
8
+ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
9
+ import React, { memo, useCallback, useEffect, useMemo, useState } from 'react';
10
+ import { gutter } from '@coinbase/cds-common/tokens/sizing';
11
+ import { chartCompactHeight, chartHeight } from '@coinbase/cds-common/tokens/sparkline';
12
+ import { debounce } from '@coinbase/cds-common/utils/debounce';
13
+ import { getAccessibleColor } from '@coinbase/cds-common/utils/getAccessibleColor';
14
+ import { useSparklineCoordinates } from '@coinbase/cds-common/visualizations/useSparklineCoordinates';
15
+ import { chartFallbackNegative, chartFallbackPositive } from '@coinbase/cds-lottie-files';
16
+ import { emptyArray, isStorybook, noop } from '@coinbase/cds-utils';
17
+ import { cx, useTheme } from '@coinbase/cds-web';
18
+ import { Lottie } from '@coinbase/cds-web/animation';
19
+ import { useDimensions } from '@coinbase/cds-web/hooks/useDimensions';
20
+ import { HStack, VStack } from '@coinbase/cds-web/layout';
21
+ import { Box } from '@coinbase/cds-web/layout/Box';
22
+ import { getBrowserGlobals } from '@coinbase/cds-web/utils/browser';
23
+ import { VisualizationContainer } from '@coinbase/cds-web/visualizations/VisualizationContainer';
24
+ import isEqual from 'lodash/isEqual';
25
+ import isObject from 'lodash/isObject';
26
+ import { InnerSparklineInteractiveProvider } from './InnerSparklineInteractiveProvider';
27
+ import { SparklineInteractiveHoverDate } from './SparklineInteractiveHoverDate';
28
+ import { SparklineInteractiveHoverPrice } from './SparklineInteractiveHoverPrice';
29
+ import { SparklineInteractiveLineVertical } from './SparklineInteractiveLineVertical';
30
+ import { SparklineInteractiveMarkerDates } from './SparklineInteractiveMarkerDates';
31
+ import { SparklineInteractivePaths } from './SparklineInteractivePaths';
32
+ import { SparklineInteractivePeriodSelector } from './SparklineInteractivePeriodSelector';
33
+ import { SparklineInteractiveProvider, useSparklineInteractiveContext } from './SparklineInteractiveProvider';
34
+ import { SparklineInteractiveScrubHandler } from './SparklineInteractiveScrubHandler';
35
+ import { SparklineInteractiveScrubProvider } from './SparklineInteractiveScrubProvider';
36
+ import { useSparklineInteractiveConstants } from './useSparklineInteractiveConstants';
37
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
38
+ export * from '@coinbase/cds-common/types/Chart';
39
+ const DefaultFallback = /*#__PURE__*/memo(_ref => {
40
+ let {
41
+ fallbackType
42
+ } = _ref;
43
+ // don't show lottie animation in story book
44
+ const skipLottie = isStorybook();
45
+ const source = fallbackType === 'negative' ? chartFallbackNegative : chartFallbackPositive;
46
+ return !skipLottie && /*#__PURE__*/_jsx(Lottie, {
47
+ autoplay: true,
48
+ loop: true,
49
+ height: "100%",
50
+ source: source,
51
+ width: "100%"
52
+ });
53
+ });
54
+ const mobileLayoutBreakpoint = 650;
55
+ function SparklineInteractiveContentWithGeneric(_ref2) {
56
+ let {
57
+ data,
58
+ periods,
59
+ defaultPeriod,
60
+ onPeriodChanged,
61
+ strokeColor,
62
+ onScrub = noop,
63
+ onScrubStart = noop,
64
+ onScrubEnd = noop,
65
+ formatDate,
66
+ fallback = null,
67
+ hidePeriodSelector = false,
68
+ disableScrubbing = false,
69
+ fill = true,
70
+ yAxisScalingFactor = 1.0,
71
+ compact,
72
+ formatHoverDate,
73
+ formatHoverPrice,
74
+ headerNode,
75
+ fallbackType = 'positive',
76
+ timePeriodGutter,
77
+ hoverData,
78
+ periodSelectorPlacement = 'above',
79
+ className,
80
+ classNames,
81
+ style,
82
+ styles,
83
+ headerTestID
84
+ } = _ref2;
85
+ const [isScrubbing, setIsScrubbing] = useState(false);
86
+ const [isMarkerDateVisible, setIsMarkerDateVisible] = useState(false);
87
+ const innerSparklineInteractiveHeight = compact ? chartCompactHeight : chartHeight;
88
+ const {
89
+ isFallbackVisible,
90
+ showFallback
91
+ } = useSparklineInteractiveContext();
92
+ const {
93
+ observe: containerRef,
94
+ width: containerWidth
95
+ } = useDimensions();
96
+ const isMobileLayout = containerWidth > 0 && containerWidth < mobileLayoutBreakpoint;
97
+ const showHeaderPeriodSelector = periodSelectorPlacement === 'above' && !hidePeriodSelector;
98
+ const showBottomMarkerDates = useMemo(() => periodSelectorPlacement === 'above' || periodSelectorPlacement === 'below' && hidePeriodSelector || isMarkerDateVisible, [isMarkerDateVisible, periodSelectorPlacement, hidePeriodSelector]);
99
+ const color = strokeColor;
100
+ const [selectedPeriod, setSelectedPeriod] = useState(defaultPeriod);
101
+ const theme = useTheme();
102
+ const lineVerticalColor = useMemo(() => {
103
+ const lineColor = color !== 'auto' ? color : getAccessibleColor({
104
+ background: theme.color.bg,
105
+ foreground: 'auto',
106
+ usage: 'graphic'
107
+ });
108
+ return hoverData ? 'var(--color-bgLineHeavy)' : lineColor;
109
+ }, [hoverData, color, theme.color.bg]);
110
+ const dataForPeriod = useMemo(() => {
111
+ var _data$selectedPeriod;
112
+ if (!data) {
113
+ return emptyArray;
114
+ }
115
+ return (_data$selectedPeriod = data[selectedPeriod]) !== null && _data$selectedPeriod !== void 0 ? _data$selectedPeriod : emptyArray;
116
+ }, [data, selectedPeriod]);
117
+ const handleScrubStart = useCallback(() => {
118
+ if (hoverData) {
119
+ setIsScrubbing(true);
120
+ }
121
+ setIsMarkerDateVisible(true);
122
+ onScrubStart === null || onScrubStart === void 0 || onScrubStart();
123
+ }, [hoverData, onScrubStart]);
124
+ const handleScrubEnd = useCallback(() => {
125
+ if (hoverData) {
126
+ setIsScrubbing(false);
127
+ }
128
+ setIsMarkerDateVisible(false);
129
+ onScrubEnd === null || onScrubEnd === void 0 || onScrubEnd();
130
+ }, [hoverData, onScrubEnd]);
131
+
132
+ // If dataForPeriod is empty we know that we are either loading
133
+ // or backend returned bad data and we should show fallback UI.
134
+ const hasData = dataForPeriod.length > 0;
135
+ useEffect(() => {
136
+ var _data$selectedPeriod2;
137
+ // If there is no data for selected period show fallback loader
138
+ if (isObject(data) && !((_data$selectedPeriod2 = data[selectedPeriod]) !== null && _data$selectedPeriod2 !== void 0 && _data$selectedPeriod2.length) && !isFallbackVisible) {
139
+ showFallback();
140
+ }
141
+ }, [data, isFallbackVisible, selectedPeriod, showFallback]);
142
+ const updatePeriod = useCallback(period => {
143
+ if (isObject(data) && period !== selectedPeriod) {
144
+ // This can sometimes happen for newer assets which
145
+ // will have their 'all' chart data be the same as
146
+ // their 'year' chart data. In those cases we don't
147
+ // want to animate out the min/max since we rely on
148
+ // AnimatedSparklineInteractivePath to animate those components back in -
149
+ // and AnimatedSparklineInteractivePath will not trigger an animation
150
+ // if it's chartData is the same between re-renders
151
+ if (!isEqual(data[period], data[selectedPeriod])) {
152
+ // minMaxOpacity.setValue(0);
153
+ }
154
+ setSelectedPeriod(period);
155
+ onPeriodChanged === null || onPeriodChanged === void 0 || onPeriodChanged(period);
156
+ }
157
+ }, [data, selectedPeriod, onPeriodChanged /* , minMaxOpacity */]);
158
+ const {
159
+ chartWidth
160
+ } = useSparklineInteractiveConstants();
161
+ const {
162
+ path,
163
+ area,
164
+ getMarker
165
+ } = useSparklineCoordinates({
166
+ data: dataForPeriod,
167
+ width: chartWidth,
168
+ height: innerSparklineInteractiveHeight,
169
+ yAxisScalingFactor
170
+ });
171
+ let header;
172
+ if (headerNode) {
173
+ header = /*#__PURE__*/_jsx(Box, {
174
+ className: classNames === null || classNames === void 0 ? void 0 : classNames.header,
175
+ flexGrow: 1,
176
+ paddingX: !isMobileLayout ? gutter : 0,
177
+ style: styles === null || styles === void 0 ? void 0 : styles.header,
178
+ testID: headerTestID,
179
+ children: headerNode
180
+ });
181
+ }
182
+ const periodSelector = /*#__PURE__*/_jsx(SparklineInteractivePeriodSelector, {
183
+ color: color,
184
+ periods: periods,
185
+ selectedPeriod: selectedPeriod,
186
+ setSelectedPeriod: updatePeriod
187
+ });
188
+ const rootStyles = useMemo(() => _objectSpread(_objectSpread({
189
+ width: '100%'
190
+ }, style), styles === null || styles === void 0 ? void 0 : styles.root), [style, styles === null || styles === void 0 ? void 0 : styles.root]);
191
+ return /*#__PURE__*/_jsxs("div", {
192
+ ref: containerRef,
193
+ className: cx(className, classNames === null || classNames === void 0 ? void 0 : classNames.root),
194
+ style: rootStyles,
195
+ children: [isMobileLayout && showHeaderPeriodSelector && /*#__PURE__*/_jsx(Box, {
196
+ paddingBottom: 2,
197
+ width: "100%",
198
+ children: periodSelector
199
+ }), (!!headerNode || !isMobileLayout && showHeaderPeriodSelector) && /*#__PURE__*/_jsxs(Box, {
200
+ alignItems: "center",
201
+ justifyContent: "space-between",
202
+ paddingBottom: 2,
203
+ children: [header !== null && header !== void 0 ? header : /*#__PURE__*/_jsx("div", {}), !isMobileLayout && showHeaderPeriodSelector && /*#__PURE__*/_jsx(Box, {
204
+ flexGrow: 0,
205
+ children: periodSelector
206
+ })]
207
+ }), /*#__PURE__*/_jsxs(SparklineInteractiveScrubProvider, {
208
+ children: [/*#__PURE__*/_jsxs(VStack, {
209
+ paddingBottom: (formatHoverDate || formatHoverPrice) && 1,
210
+ children: [!!formatHoverDate && /*#__PURE__*/_jsx(SparklineInteractiveHoverDate, {}), !!formatHoverPrice && /*#__PURE__*/_jsx(SparklineInteractiveHoverPrice, {})]
211
+ }), /*#__PURE__*/_jsx(VisualizationContainer, {
212
+ height: innerSparklineInteractiveHeight,
213
+ width: "100%",
214
+ children: _ref3 => {
215
+ let {
216
+ width,
217
+ height
218
+ } = _ref3;
219
+ return /*#__PURE__*/_jsx(InnerSparklineInteractiveProvider, {
220
+ height: height,
221
+ width: width,
222
+ children: /*#__PURE__*/_jsx(SparklineInteractiveScrubHandler, {
223
+ disabled: disableScrubbing,
224
+ formatHoverDate: formatHoverDate,
225
+ formatHoverPrice: formatHoverPrice,
226
+ getMarker: getMarker,
227
+ onScrub: onScrub,
228
+ onScrubEnd: handleScrubEnd,
229
+ onScrubStart: handleScrubStart,
230
+ selectedPeriod: selectedPeriod,
231
+ children: /*#__PURE__*/_jsxs(Box, {
232
+ height: height,
233
+ position: "relative",
234
+ width: width,
235
+ children: [!!isFallbackVisible && /*#__PURE__*/_jsx(Box, {
236
+ height: "100%",
237
+ justifyContent: "center",
238
+ position: "absolute",
239
+ width: "100%",
240
+ children: fallback !== null && fallback !== void 0 ? fallback : /*#__PURE__*/_jsx(DefaultFallback, {
241
+ fallbackType: fallbackType
242
+ })
243
+ }), /*#__PURE__*/_jsx(Box, {
244
+ height: "100%",
245
+ width: "100%",
246
+ children: !!hasData && !!path && /*#__PURE__*/_jsxs(_Fragment, {
247
+ children: [/*#__PURE__*/_jsx(SparklineInteractivePaths, {
248
+ area: area,
249
+ compact: compact,
250
+ fill: fill,
251
+ hoverData: hoverData,
252
+ path: path,
253
+ selectedPeriod: selectedPeriod,
254
+ showHoverData: isScrubbing,
255
+ strokeColor: color,
256
+ yAxisScalingFactor: yAxisScalingFactor
257
+ }), /*#__PURE__*/_jsx(SparklineInteractiveLineVertical, {
258
+ color: lineVerticalColor
259
+ })]
260
+ })
261
+ })]
262
+ })
263
+ })
264
+ });
265
+ }
266
+ })]
267
+ }), /*#__PURE__*/_jsxs(HStack, {
268
+ alignItems: "flex-end",
269
+ minHeight: 50,
270
+ width: "100%",
271
+ children: [showBottomMarkerDates && /*#__PURE__*/_jsx(SparklineInteractiveMarkerDates, {
272
+ formatDate: formatDate,
273
+ getMarker: getMarker,
274
+ selectedPeriod: selectedPeriod,
275
+ timePeriodGutter: timePeriodGutter
276
+ }), periodSelectorPlacement === 'below' && !isMarkerDateVisible && !hidePeriodSelector && periodSelector]
277
+ })]
278
+ });
279
+ }
280
+
281
+ // typescript doesn't understand the memo with the generic so it gets casted to a base react component
282
+ export const SparklineInteractiveContent = /*#__PURE__*/memo(SparklineInteractiveContentWithGeneric);
283
+ function SparklineInteractiveWithGeneric(_ref4) {
284
+ let {
285
+ compact
286
+ } = _ref4,
287
+ props = _objectWithoutProperties(_ref4, _excluded);
288
+ const [resizeKey, setResizeKey] = useState(0);
289
+ // eslint-disable-next-line react-hooks/exhaustive-deps
290
+ const resizeHandler = useCallback(debounce(() => {
291
+ // no resizing on percy
292
+ if (!isStorybook()) {
293
+ setResizeKey(prev => prev + 1);
294
+ }
295
+ }, 300), []);
296
+ useEffect(() => {
297
+ var _getBrowserGlobals;
298
+ (_getBrowserGlobals = getBrowserGlobals()) === null || _getBrowserGlobals === void 0 || (_getBrowserGlobals = _getBrowserGlobals.window) === null || _getBrowserGlobals === void 0 || _getBrowserGlobals.addEventListener('resize', resizeHandler);
299
+ return () => {
300
+ var _getBrowserGlobals2;
301
+ (_getBrowserGlobals2 = getBrowserGlobals()) === null || _getBrowserGlobals2 === void 0 || (_getBrowserGlobals2 = _getBrowserGlobals2.window) === null || _getBrowserGlobals2 === void 0 || _getBrowserGlobals2.removeEventListener('resize', resizeHandler);
302
+ };
303
+ }, [resizeHandler]);
304
+ return /*#__PURE__*/_jsx(SparklineInteractiveProvider, {
305
+ compact: compact,
306
+ children: /*#__PURE__*/_jsx(SparklineInteractiveContent, _objectSpread({
307
+ compact: compact
308
+ }, props))
309
+ }, resizeKey);
310
+ }
311
+
312
+ // typescript doesn't understand the memo with the generic so it gets casted to a base react component
313
+ export const SparklineInteractive = /*#__PURE__*/memo(SparklineInteractiveWithGeneric);
@@ -0,0 +1,105 @@
1
+ import 'd3-transition'; // Important! do not remove this, it sets up the linkage so you can use select().transition()
2
+
3
+ import React, { memo, useCallback, useEffect, useMemo, useRef } from 'react';
4
+ import { animatedPathConfig } from '@coinbase/cds-common/animation/sparkline';
5
+ import { useValueChanges } from '@coinbase/cds-common/hooks/useValueChanges';
6
+ import { interpolatePath } from 'd3-interpolate-path';
7
+ import { select } from 'd3-selection';
8
+ import { SparklineArea } from '../SparklineArea';
9
+ import { SparklineGradient } from '../SparklineGradient';
10
+ import { useSparklineInteractiveContext } from './SparklineInteractiveProvider';
11
+ import { useSparklineInteractiveConstants } from './useSparklineInteractiveConstants';
12
+ import { jsx as _jsx } from "react/jsx-runtime";
13
+ const {
14
+ duration,
15
+ easing
16
+ } = animatedPathConfig;
17
+ export const SparklineInteractiveAnimatedPath = /*#__PURE__*/memo(_ref => {
18
+ let {
19
+ d = '',
20
+ color,
21
+ selectedPeriod,
22
+ area,
23
+ yAxisScalingFactor,
24
+ initialPath,
25
+ initialArea
26
+ } = _ref;
27
+ const pathRef = useRef(null);
28
+ const areaRef = useRef(null);
29
+ const {
30
+ chartWidth,
31
+ chartHeight
32
+ } = useSparklineInteractiveConstants();
33
+ const {
34
+ isFallbackVisible,
35
+ hideFallback
36
+ } = useSparklineInteractiveContext();
37
+
38
+ // Only tween animation on period changes
39
+ const {
40
+ hasNotChanged: skipAnimation,
41
+ addPreviousValue: addPreviousPeriod
42
+ } = useValueChanges(selectedPeriod);
43
+ const {
44
+ previousValue: previousPath,
45
+ newValue: newPath,
46
+ hasChanged: shouldUpdatePath,
47
+ addPreviousValue: addPreviousPath
48
+ } = useValueChanges(d);
49
+ const {
50
+ previousValue: previousArea,
51
+ newValue: newArea,
52
+ hasChanged: shouldUpdateArea,
53
+ addPreviousValue: addPreviousArea
54
+ } = useValueChanges(area !== null && area !== void 0 ? area : '');
55
+ const pathInterpolator = useMemo(() => interpolatePath(previousPath !== null && previousPath !== void 0 ? previousPath : initialPath, newPath), [previousPath, initialPath, newPath]);
56
+ const areaInterpolator = useMemo(() => interpolatePath(previousArea !== null && previousArea !== void 0 ? previousArea : initialArea, newArea), [previousArea, initialArea, newArea]);
57
+ const updatePathWithoutAnimation = useCallback(() => {
58
+ select(pathRef.current).attr('d', pathInterpolator(1));
59
+ select(areaRef.current).attr('d', areaInterpolator(1));
60
+ }, [areaInterpolator, pathInterpolator]);
61
+ const playAnimation = useCallback(() => {
62
+ select(pathRef.current).transition().duration(duration).ease(easing).attrTween('d', function tween() {
63
+ const previous = select(this).attr('d');
64
+ const current = d;
65
+ return interpolatePath(previous !== null && previous !== void 0 ? previous : initialPath, current);
66
+ });
67
+ if (area) {
68
+ select(areaRef.current).transition().duration(duration).ease(easing).attrTween('d', function tween() {
69
+ const previous = select(this).attr('d');
70
+ const current = area;
71
+ return interpolatePath(previous !== null && previous !== void 0 ? previous : initialArea, current);
72
+ });
73
+ }
74
+ }, [area, d, initialArea, initialPath]);
75
+ useEffect(() => {
76
+ addPreviousPeriod(selectedPeriod);
77
+ }, [addPreviousPeriod, selectedPeriod]);
78
+ useEffect(() => {
79
+ // only update these values when they are used
80
+ addPreviousArea(newArea);
81
+ addPreviousPath(newPath);
82
+ if (shouldUpdatePath) {
83
+ if (isFallbackVisible) {
84
+ hideFallback();
85
+ updatePathWithoutAnimation();
86
+ } else if (skipAnimation) {
87
+ updatePathWithoutAnimation();
88
+ } else {
89
+ playAnimation();
90
+ }
91
+ } else if (shouldUpdateArea) {
92
+ updatePathWithoutAnimation();
93
+ }
94
+ }, [addPreviousArea, addPreviousPath, hideFallback, isFallbackVisible, newArea, newPath, playAnimation, shouldUpdateArea, shouldUpdatePath, skipAnimation, updatePathWithoutAnimation]);
95
+ return /*#__PURE__*/_jsx(SparklineGradient, {
96
+ ref: pathRef,
97
+ color: color,
98
+ height: chartHeight,
99
+ width: chartWidth,
100
+ yAxisScalingFactor: yAxisScalingFactor,
101
+ children: !!area && /*#__PURE__*/_jsx(SparklineArea, {
102
+ ref: areaRef
103
+ })
104
+ });
105
+ });
@@ -0,0 +1,2 @@
1
+ .cds-resetFadeCss-r1flhiq9{opacity:0;}
2
+ .cds-textCss-t1ofwd95{display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}
@@ -0,0 +1,26 @@
1
+ import React, { memo, useCallback } from 'react';
2
+ import { cx } from '@coinbase/cds-web';
3
+ import { TextLabel2 } from '@coinbase/cds-web/typography/TextLabel2';
4
+ import { useSparklineInteractiveScrubContext } from './SparklineInteractiveScrubProvider';
5
+ import { jsx as _jsx } from "react/jsx-runtime";
6
+ const resetFadeCss = "cds-resetFadeCss-r1flhiq9";
7
+ const textCss = "cds-textCss-t1ofwd95";
8
+ export const SparklineInteractiveHoverDate = /*#__PURE__*/memo(() => {
9
+ const {
10
+ setHoverDateDOMNode
11
+ } = useSparklineInteractiveScrubContext();
12
+ const dateString = new Date().toLocaleString();
13
+ const setupDateRef = useCallback(ref => {
14
+ setHoverDateDOMNode(ref !== null && ref !== void 0 ? ref : null);
15
+ }, [setHoverDateDOMNode]);
16
+ return /*#__PURE__*/_jsx(TextLabel2, {
17
+ tabularNumbers: true,
18
+ as: "div",
19
+ children: /*#__PURE__*/_jsx("span", {
20
+ ref: setupDateRef,
21
+ className: cx(resetFadeCss, textCss),
22
+ children: dateString
23
+ })
24
+ });
25
+ });
26
+ import "./SparklineInteractiveHoverDate.css";
@@ -0,0 +1,2 @@
1
+ .cds-resetFadeCss-r1armfip{opacity:0;}
2
+ .cds-textCss-t1es6xjy{display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}
@@ -0,0 +1,24 @@
1
+ import React, { memo, useCallback } from 'react';
2
+ import { cx } from '@coinbase/cds-web';
3
+ import { TextLabel2 } from '@coinbase/cds-web/typography/TextLabel2';
4
+ import { useSparklineInteractiveScrubContext } from './SparklineInteractiveScrubProvider';
5
+ import { jsx as _jsx } from "react/jsx-runtime";
6
+ const resetFadeCss = "cds-resetFadeCss-r1armfip";
7
+ const textCss = "cds-textCss-t1es6xjy";
8
+ export const SparklineInteractiveHoverPrice = /*#__PURE__*/memo(() => {
9
+ const {
10
+ setHoverPriceDOMNode
11
+ } = useSparklineInteractiveScrubContext();
12
+ const setupPriceRef = useCallback(ref => {
13
+ setHoverPriceDOMNode(ref !== null && ref !== void 0 ? ref : null);
14
+ }, [setHoverPriceDOMNode]);
15
+ return /*#__PURE__*/_jsx(TextLabel2, {
16
+ tabularNumbers: true,
17
+ as: "div",
18
+ children: /*#__PURE__*/_jsx("span", {
19
+ ref: setupPriceRef,
20
+ className: cx(resetFadeCss, textCss)
21
+ })
22
+ });
23
+ });
24
+ import "./SparklineInteractiveHoverPrice.css";
@@ -0,0 +1,4 @@
1
+ .cds-resetFadeCss-r1p330gi{opacity:0;}
2
+ .cds-verticalLineCss-vjctcux{position:absolute;pointer-events:none;width:100%;height:100%;overflow:hidden;}
3
+ .cds-lineContainerCss-lfwfzju{width:2px;height:100%;}
4
+ .cds-maskCss-mc4jbg4{width:100%;height:100%;opacity:0;position:absolute;left:0;right:0;top:0;bottom:0;}
@@ -0,0 +1,65 @@
1
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
2
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
3
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
4
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
5
+ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
6
+ import React, { memo, useCallback } from 'react';
7
+ import { borderWidth, lineDashArray } from '@coinbase/cds-common/tokens/sparkline';
8
+ import { cx } from '@coinbase/cds-web';
9
+ import { useSparklineInteractiveContext } from './SparklineInteractiveProvider';
10
+ import { useSparklineInteractiveScrubContext } from './SparklineInteractiveScrubProvider';
11
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
12
+ const resetFadeCss = "cds-resetFadeCss-r1p330gi";
13
+ const verticalLineCss = "cds-verticalLineCss-vjctcux";
14
+ const lineContainerCss = "cds-lineContainerCss-lfwfzju";
15
+ const maskCss = "cds-maskCss-mc4jbg4";
16
+ const lineProps = {
17
+ x1: 0,
18
+ x2: 0,
19
+ y1: 0,
20
+ y2: 0,
21
+ strokeDasharray: lineDashArray.join(','),
22
+ strokeWidth: borderWidth
23
+ };
24
+ export const SparklineInteractiveLineVertical = /*#__PURE__*/memo(_ref => {
25
+ let {
26
+ color
27
+ } = _ref;
28
+ const {
29
+ setLineDOMNode,
30
+ setMaskDOMNode
31
+ } = useSparklineInteractiveScrubContext();
32
+ const {
33
+ height
34
+ } = useSparklineInteractiveContext();
35
+ const setupLineRef = useCallback(ref => {
36
+ setLineDOMNode(ref !== null && ref !== void 0 ? ref : null);
37
+ }, [setLineDOMNode]);
38
+ const setupMaskRef = useCallback(ref => {
39
+ setMaskDOMNode(ref !== null && ref !== void 0 ? ref : null);
40
+ }, [setMaskDOMNode]);
41
+ const maskStyle = {
42
+ backgroundColor: 'var(--color-bg)'
43
+ };
44
+
45
+ // hook up the line and mask
46
+ return /*#__PURE__*/_jsxs("div", {
47
+ className: verticalLineCss,
48
+ children: [/*#__PURE__*/_jsx("div", {
49
+ ref: setupMaskRef,
50
+ className: cx(maskCss, resetFadeCss),
51
+ style: maskStyle
52
+ }), /*#__PURE__*/_jsx("div", {
53
+ ref: setupLineRef,
54
+ className: cx(lineContainerCss, resetFadeCss),
55
+ children: /*#__PURE__*/_jsx("svg", {
56
+ className: lineContainerCss,
57
+ children: /*#__PURE__*/_jsx("line", _objectSpread(_objectSpread({}, lineProps), {}, {
58
+ stroke: color,
59
+ y2: height
60
+ }))
61
+ })
62
+ })]
63
+ });
64
+ });
65
+ import "./SparklineInteractiveLineVertical.css";
@@ -0,0 +1 @@
1
+ .cds-fadeInCss-f1yvdjq7.cds-fadeInCss-f1yvdjq7{-webkit-animation:cdsSparklineInteractiveFadeIn-cds-fadeInCss-f1yvdjq7 200ms cubic-bezier(0.6,0,0.15,1);animation:cdsSparklineInteractiveFadeIn-cds-fadeInCss-f1yvdjq7 200ms cubic-bezier(0.6,0,0.15,1);opacity:1;}@-webkit-keyframes cdsSparklineInteractiveFadeIn-cds-fadeInCss-f1yvdjq7{0%{opacity:0;}100%{opacity:1;}}@keyframes cdsSparklineInteractiveFadeIn-cds-fadeInCss-f1yvdjq7{0%{opacity:0;}100%{opacity:1;}}
@@ -0,0 +1,84 @@
1
+ import React, { memo, useCallback, useMemo, useState } from 'react';
2
+ import { fadeDuration } from '@coinbase/cds-common/tokens/sparkline';
3
+ import { useDateLookup } from '@coinbase/cds-common/visualizations/useDateLookup';
4
+ import { cubicBezier } from '@coinbase/cds-web/animation/convertMotionConfig';
5
+ import { HStack } from '@coinbase/cds-web/layout';
6
+ import { TextLabel2 } from '@coinbase/cds-web/typography/TextLabel2';
7
+ import times from 'lodash/times';
8
+ import { jsx as _jsx } from "react/jsx-runtime";
9
+ const fadeInCss = "cds-fadeInCss-f1yvdjq7";
10
+ const labelWidth = 125;
11
+ const noPointerEvents = {
12
+ pointerEvents: 'none'
13
+ };
14
+ const SparklineInteractiveMarkerDate = /*#__PURE__*/memo(_ref => {
15
+ let {
16
+ getFormattedDate,
17
+ containerOffsetLeft
18
+ } = _ref;
19
+ const [xPos, setXPos] = useState(0);
20
+ const setupRef = useCallback(ref => {
21
+ if (ref) {
22
+ setXPos(ref.offsetLeft + ref.offsetWidth / 2 - containerOffsetLeft);
23
+ }
24
+ }, [containerOffsetLeft]);
25
+ const dateStr = getFormattedDate(xPos);
26
+
27
+ // take up space while loading so when it finishes loading there is no jump
28
+ const fallback = /*#__PURE__*/_jsx("span", {
29
+ style: {
30
+ visibility: 'hidden'
31
+ },
32
+ children: "-"
33
+ });
34
+ return /*#__PURE__*/_jsx("span", {
35
+ ref: setupRef,
36
+ children: /*#__PURE__*/_jsx(TextLabel2, {
37
+ as: "span",
38
+ color: "fgMuted",
39
+ textAlign: "center",
40
+ children: dateStr || fallback
41
+ })
42
+ });
43
+ });
44
+ function SparklineInteractiveMarkerDatesWithGeneric(_ref2) {
45
+ let {
46
+ formatDate,
47
+ selectedPeriod,
48
+ getMarker,
49
+ timePeriodGutter = 2
50
+ } = _ref2;
51
+ const [numberOfLabels, setNumberOfLabels] = useState(0);
52
+ const [containerOffsetLeft, setContainerOffsetLeft] = useState(0);
53
+ const getFormattedDate = useDateLookup({
54
+ getMarker,
55
+ formatDate,
56
+ selectedPeriod
57
+ });
58
+ const setupRef = useCallback(ref => {
59
+ if (ref) {
60
+ const numberOfLabelsFromWidth = Math.floor(ref.offsetWidth / labelWidth);
61
+ setNumberOfLabels(Math.max(numberOfLabelsFromWidth, 4));
62
+ setContainerOffsetLeft(ref.offsetLeft);
63
+ }
64
+ }, []);
65
+ const markers = useMemo(() => {
66
+ return times(numberOfLabels).map((_, i) => {
67
+ return /*#__PURE__*/_jsx(SparklineInteractiveMarkerDate, {
68
+ containerOffsetLeft: containerOffsetLeft,
69
+ getFormattedDate: getFormattedDate
70
+ }, i);
71
+ });
72
+ }, [getFormattedDate, numberOfLabels, containerOffsetLeft]);
73
+ return /*#__PURE__*/_jsx(HStack, {
74
+ ref: setupRef,
75
+ className: fadeInCss,
76
+ justifyContent: "space-between",
77
+ paddingX: timePeriodGutter,
78
+ style: noPointerEvents,
79
+ width: "100%",
80
+ children: markers
81
+ }, selectedPeriod);
82
+ }
83
+ export const SparklineInteractiveMarkerDates = /*#__PURE__*/memo(SparklineInteractiveMarkerDatesWithGeneric);
84
+ import "./SparklineInteractiveMarkerDates.css";