@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,113 @@
1
+ import React, { memo, useCallback, useEffect, useMemo, useRef } from 'react';
2
+ import { useValueChanges } from '@coinbase/cds-common/hooks/useValueChanges';
3
+ import * as interpolate from 'd3-interpolate-path';
4
+ import { SparklineArea } from '../SparklineArea';
5
+ import { SparklineGradient } from '../SparklineGradient';
6
+ import { useSparklineInteractiveContext } from './SparklineInteractiveProvider';
7
+ import { useInterruptiblePathAnimation } from './useInterruptiblePathAnimation';
8
+ import { useSparklineInteractiveConstants } from './useSparklineInteractiveConstants';
9
+ import { jsx as _jsx } from "react/jsx-runtime";
10
+ export const SparklineInteractiveAnimatedPath = /*#__PURE__*/memo(_ref => {
11
+ let {
12
+ d = '',
13
+ color,
14
+ selectedPeriod,
15
+ area,
16
+ yAxisScalingFactor,
17
+ initialPath,
18
+ initialArea
19
+ } = _ref;
20
+ const {
21
+ isFallbackVisible,
22
+ hideFallback,
23
+ animateMinMaxIn,
24
+ compact
25
+ } = useSparklineInteractiveContext();
26
+ const pathRef = useRef(null);
27
+ const areaRef = useRef(null);
28
+
29
+ // Only tween animation on period changes
30
+ const {
31
+ hasNotChanged: skipAnimation,
32
+ addPreviousValue: addPreviousPeriod
33
+ } = useValueChanges(selectedPeriod);
34
+ const {
35
+ previousValue: previousPath,
36
+ newValue: newPath,
37
+ hasChanged: shouldUpdatePath,
38
+ addPreviousValue: addPreviousPath
39
+ } = useValueChanges(d);
40
+ const {
41
+ previousValue: previousArea,
42
+ newValue: newArea,
43
+ hasChanged: shouldUpdateArea,
44
+ addPreviousValue: addPreviousArea
45
+ } = useValueChanges(area != null ? area : '');
46
+ const pathInterpolator = useMemo(() => interpolate.interpolatePath(previousPath != null ? previousPath : initialPath, newPath), [previousPath, initialPath, newPath]);
47
+ const areaInterpolator = useMemo(() => interpolate.interpolatePath(previousArea != null ? previousArea : initialArea, newArea), [previousArea, initialArea, newArea]);
48
+ const animationListener = useCallback(_ref2 => {
49
+ var _pathRef$current, _areaRef$current;
50
+ let {
51
+ value
52
+ } = _ref2;
53
+ const val = Number(value.toFixed(4));
54
+ (_pathRef$current = pathRef.current) == null || _pathRef$current.setNativeProps({
55
+ d: pathInterpolator(val)
56
+ });
57
+ (_areaRef$current = areaRef.current) == null || _areaRef$current.setNativeProps({
58
+ d: areaInterpolator(val)
59
+ });
60
+ }, [areaInterpolator, pathInterpolator]);
61
+ const updatePathWithoutAnimation = useCallback(() => {
62
+ var _pathRef$current2, _areaRef$current2;
63
+ (_pathRef$current2 = pathRef.current) == null || _pathRef$current2.setNativeProps({
64
+ d: pathInterpolator(1)
65
+ });
66
+ (_areaRef$current2 = areaRef.current) == null || _areaRef$current2.setNativeProps({
67
+ d: areaInterpolator(1)
68
+ });
69
+ animateMinMaxIn.start();
70
+ }, [animateMinMaxIn, areaInterpolator, pathInterpolator]);
71
+ const playAnimation = useInterruptiblePathAnimation({
72
+ animationListener,
73
+ onInterrupt: updatePathWithoutAnimation
74
+ });
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
+ }, [hideFallback, shouldUpdatePath, shouldUpdateArea, skipAnimation, updatePathWithoutAnimation, playAnimation, isFallbackVisible, addPreviousPath, addPreviousArea, newArea, newPath]);
95
+ const {
96
+ chartWidth,
97
+ chartHeight
98
+ } = useSparklineInteractiveConstants({
99
+ compact
100
+ });
101
+ return /*#__PURE__*/_jsx(SparklineGradient, {
102
+ ref: pathRef,
103
+ color: color,
104
+ height: chartHeight,
105
+ path: initialPath,
106
+ width: chartWidth,
107
+ yAxisScalingFactor: yAxisScalingFactor,
108
+ children: !!area && /*#__PURE__*/_jsx(SparklineArea, {
109
+ ref: areaRef,
110
+ area: initialArea
111
+ })
112
+ });
113
+ });
@@ -0,0 +1,131 @@
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, { forwardRef, useImperativeHandle, useMemo, useRef } from 'react';
3
+ import { Animated, StyleSheet, TextInput } from 'react-native';
4
+ import { useTheme } from '@coinbase/cds-mobile/hooks/useTheme';
5
+ import { useSparklineInteractiveContext } from './SparklineInteractiveProvider';
6
+ import { useSparklineInteractiveConstants } from './useSparklineInteractiveConstants';
7
+ import { jsx as _jsx } from "react/jsx-runtime";
8
+ export function setTransform(x, elWidth, containerWidth, transform, gutter) {
9
+ let newX = x - elWidth / 2;
10
+ newX = Math.max(gutter, newX);
11
+ newX = Math.min(newX, containerWidth - elWidth - gutter);
12
+ transform.setValue({
13
+ x: newX,
14
+ y: 0
15
+ });
16
+ }
17
+ const styles = StyleSheet.create({
18
+ outer: {
19
+ alignItems: 'center',
20
+ justifyContent: 'center',
21
+ width: '100%'
22
+ },
23
+ caption: {
24
+ alignSelf: 'center',
25
+ position: 'absolute',
26
+ left: 0
27
+ }
28
+ });
29
+ const MAX_MEASURE_ITERATIONS = 5;
30
+ const SparklineInteractiveHoverDateWithGeneric = /*#__PURE__*/forwardRef((_ref, ref) => {
31
+ let {
32
+ formatHoverDate,
33
+ shouldTakeUpHeight
34
+ } = _ref;
35
+ const theme = useTheme();
36
+ const {
37
+ hoverDateOpacity,
38
+ gutter
39
+ } = useSparklineInteractiveContext();
40
+ const {
41
+ SparklineInteractiveMinMaxLabelHeight,
42
+ chartWidth
43
+ } = useSparklineInteractiveConstants({});
44
+ const transform = useRef(new Animated.ValueXY({
45
+ x: 0,
46
+ y: 0
47
+ })).current;
48
+ const textInputRef = useRef(null);
49
+
50
+ // period => number mapping
51
+ const measuredWidth = useRef({});
52
+ const measureIterations = useRef({});
53
+ // if we have no gutter the min/max label needs some space so it's not right up against the edge of the screen
54
+ const minGutter = gutter === 0 ? theme.space['1'] : 0;
55
+ useImperativeHandle(ref, () => ({
56
+ update: params => {
57
+ var _textInputRef$current, _measureIterations$cu;
58
+ const {
59
+ point: {
60
+ x,
61
+ date
62
+ },
63
+ period
64
+ } = params;
65
+
66
+ // the second conditional is to let typescript know x is always defined after this line
67
+ if (!Number.isFinite(x) || x === undefined) {
68
+ return;
69
+ }
70
+ const text = formatHoverDate == null ? void 0 : formatHoverDate(date, period);
71
+ if (!text) {
72
+ return;
73
+ }
74
+
75
+ // BAD: We only disabled this lint rule to enable eslint upgrade after this component was implemented. These apis should never be used.
76
+ // Usage in this component are known making this a high risk component. Contact team for more information.
77
+
78
+ (_textInputRef$current = textInputRef.current) == null || _textInputRef$current.setNativeProps({
79
+ text: formatHoverDate == null ? void 0 : formatHoverDate(date, period)
80
+ });
81
+ measureIterations.current[period] = (_measureIterations$cu = measureIterations.current[period]) != null ? _measureIterations$cu : 0;
82
+ if (measureIterations.current[period] > MAX_MEASURE_ITERATIONS) {
83
+ const currWidth = measuredWidth.current[period];
84
+ setTransform(x, currWidth, chartWidth, transform, minGutter);
85
+ } else {
86
+ var _textInputRef$current2;
87
+ (_textInputRef$current2 = textInputRef.current) == null || _textInputRef$current2.measure((ox, oy, width) => {
88
+ var _measuredWidth$curren;
89
+ measureIterations.current[period] += 1;
90
+ measuredWidth.current[period] = Math.max(width, (_measuredWidth$curren = measuredWidth.current[period]) != null ? _measuredWidth$curren : 0);
91
+ setTransform(x, measuredWidth.current[period], chartWidth, transform, minGutter);
92
+ });
93
+ }
94
+ }
95
+ }));
96
+ const rootStyle = useMemo(() => {
97
+ return _extends({
98
+ position: shouldTakeUpHeight ? 'relative' : 'absolute',
99
+ opacity: hoverDateOpacity,
100
+ backgroundColor: theme.color.bg,
101
+ height: SparklineInteractiveMinMaxLabelHeight
102
+ }, styles.outer);
103
+ }, [SparklineInteractiveMinMaxLabelHeight, hoverDateOpacity, shouldTakeUpHeight, theme.color.bg]);
104
+ const innerStyle = useMemo(() => {
105
+ return _extends({}, styles.caption, {
106
+ transform: transform.getTranslateTransform()
107
+ });
108
+ }, [transform]);
109
+ const textInputStyle = useMemo(() => {
110
+ return {
111
+ fontSize: theme.fontSize.label2,
112
+ lineHeight: theme.lineHeight.label2,
113
+ fontFamily: theme.fontFamily.label2,
114
+ color: theme.color.fgMuted
115
+ };
116
+ }, [theme.color.fgMuted, theme.fontFamily.label2, theme.fontSize.label2, theme.lineHeight.label2]);
117
+ return /*#__PURE__*/_jsx(Animated.View, {
118
+ pointerEvents: "none",
119
+ style: rootStyle,
120
+ children: /*#__PURE__*/_jsx(Animated.View, {
121
+ style: innerStyle,
122
+ children: /*#__PURE__*/_jsx(TextInput, {
123
+ ref: textInputRef,
124
+ accessibilityHint: "Text input field",
125
+ accessibilityLabel: "Text input field",
126
+ style: textInputStyle
127
+ })
128
+ })
129
+ });
130
+ });
131
+ export const SparklineInteractiveHoverDate = SparklineInteractiveHoverDateWithGeneric;
@@ -0,0 +1,99 @@
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, { memo, useMemo } from 'react';
3
+ import { Animated as RNAnimated, StyleSheet } from 'react-native';
4
+ import Animated, { useAnimatedStyle } from 'react-native-reanimated';
5
+ import { Line, Svg } from 'react-native-svg';
6
+ import { maskOpacity } from '@coinbase/cds-common/tokens/sparkline';
7
+ import { useTheme } from '@coinbase/cds-mobile/hooks/useTheme';
8
+ import { useSparklineInteractiveContext } from './SparklineInteractiveProvider';
9
+ import { useSparklineInteractiveConstants } from './useSparklineInteractiveConstants';
10
+ import { useSparklineInteractiveLineStyles } from './useSparklineInteractiveLineStyles';
11
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
12
+ const styles = StyleSheet.create({
13
+ wrapper: _extends({}, StyleSheet.absoluteFillObject, {
14
+ zIndex: 2
15
+ })
16
+ });
17
+ const SparklineInteractiveDottedLine = /*#__PURE__*/memo(_ref => {
18
+ let {
19
+ color,
20
+ showHoverDate
21
+ } = _ref;
22
+ const theme = useTheme();
23
+ const {
24
+ markerXPosition,
25
+ compact
26
+ } = useSparklineInteractiveContext();
27
+ const {
28
+ lineProps
29
+ } = useSparklineInteractiveLineStyles();
30
+ const {
31
+ chartHeight,
32
+ SparklineInteractiveMinMaxLabelHeight,
33
+ chartVerticalLineWidth,
34
+ chartWidth
35
+ } = useSparklineInteractiveConstants({
36
+ compact
37
+ });
38
+ const dottedLineHeight = chartHeight + SparklineInteractiveMinMaxLabelHeight * (showHoverDate ? 1 : 2);
39
+ const lineStyles = useMemo(() => {
40
+ return {
41
+ width: chartVerticalLineWidth,
42
+ height: dottedLineHeight,
43
+ top: showHoverDate ? 0 : -SparklineInteractiveMinMaxLabelHeight,
44
+ zIndex: 2
45
+ };
46
+ }, [SparklineInteractiveMinMaxLabelHeight, chartVerticalLineWidth, dottedLineHeight, showHoverDate]);
47
+ const animatedTranslateX = useAnimatedStyle(() => ({
48
+ transform: [{
49
+ translateX: markerXPosition.value
50
+ }]
51
+ }));
52
+ const dottedLinePositionStyles = useMemo(() => [lineStyles, animatedTranslateX], [lineStyles, animatedTranslateX]);
53
+ const maskStyles = useMemo(() => {
54
+ return _extends({}, StyleSheet.absoluteFillObject, {
55
+ height: dottedLineHeight,
56
+ width: chartWidth,
57
+ top: showHoverDate ? 0 : -SparklineInteractiveMinMaxLabelHeight,
58
+ backgroundColor: theme.color.bg,
59
+ opacity: maskOpacity,
60
+ zIndex: 1
61
+ });
62
+ }, [SparklineInteractiveMinMaxLabelHeight, chartWidth, dottedLineHeight, showHoverDate, theme.color.bg]);
63
+ const maskPositionStyles = useMemo(() => [maskStyles, animatedTranslateX], [maskStyles, animatedTranslateX]);
64
+ return /*#__PURE__*/_jsxs(_Fragment, {
65
+ children: [/*#__PURE__*/_jsx(Animated.View, {
66
+ style: dottedLinePositionStyles,
67
+ children: /*#__PURE__*/_jsx(Svg, {
68
+ children: /*#__PURE__*/_jsx(Line, _extends({}, lineProps, {
69
+ stroke: color,
70
+ y2: dottedLineHeight
71
+ }))
72
+ })
73
+ }), /*#__PURE__*/_jsx(Animated.View, {
74
+ style: maskPositionStyles
75
+ })]
76
+ });
77
+ });
78
+ export const SparklineInteractiveLineVertical = /*#__PURE__*/memo(_ref2 => {
79
+ let {
80
+ color,
81
+ showHoverDate
82
+ } = _ref2;
83
+ const {
84
+ markerOpacity
85
+ } = useSparklineInteractiveContext();
86
+ const rootStyle = useMemo(() => {
87
+ return _extends({}, styles.wrapper, {
88
+ opacity: markerOpacity
89
+ });
90
+ }, [markerOpacity]);
91
+ return /*#__PURE__*/_jsx(RNAnimated.View, {
92
+ pointerEvents: "none",
93
+ style: rootStyle,
94
+ children: /*#__PURE__*/_jsx(SparklineInteractiveDottedLine, {
95
+ color: color,
96
+ showHoverDate: showHoverDate
97
+ })
98
+ });
99
+ });
@@ -0,0 +1,82 @@
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, { memo, useMemo } from 'react';
3
+ import { Animated, StyleSheet } from 'react-native';
4
+ import { useDateLookup } from '@coinbase/cds-common/visualizations/useDateLookup';
5
+ import { useLayout } from '@coinbase/cds-mobile/hooks/useLayout';
6
+ import { useTheme } from '@coinbase/cds-mobile/hooks/useTheme';
7
+ import { TextLabel2 } from '@coinbase/cds-mobile/typography';
8
+ import times from 'lodash/times';
9
+ import { useSparklineInteractiveContext } from './SparklineInteractiveProvider';
10
+ import { jsx as _jsx } from "react/jsx-runtime";
11
+ const numberOfLabels = 5;
12
+ const styles = StyleSheet.create({
13
+ wrapper: {
14
+ flexDirection: 'row',
15
+ justifyContent: 'space-between',
16
+ position: 'absolute',
17
+ top: 0,
18
+ left: 0,
19
+ right: 0,
20
+ zIndex: 1
21
+ },
22
+ label: {
23
+ width: 100 / numberOfLabels + "%"
24
+ }
25
+ });
26
+ const SparklineInteractiveMarkerDate = /*#__PURE__*/memo(_ref => {
27
+ let {
28
+ getFormattedDate
29
+ } = _ref;
30
+ const [label, onLayout] = useLayout();
31
+ const x = useMemo(() => {
32
+ return label.x + label.width / 2;
33
+ }, [label.width, label.x]);
34
+ return /*#__PURE__*/_jsx(TextLabel2, {
35
+ align: "center",
36
+ color: "fgMuted",
37
+ onLayout: onLayout,
38
+ paddingTop: 3,
39
+ style: styles.label,
40
+ children: getFormattedDate(x)
41
+ });
42
+ });
43
+ function SparklineInteractiveMarkerDatesWithGeneric(_ref2) {
44
+ let {
45
+ formatDate,
46
+ selectedPeriod,
47
+ getMarker,
48
+ timePeriodGutter
49
+ } = _ref2;
50
+ const {
51
+ markerOpacity
52
+ } = useSparklineInteractiveContext();
53
+ const theme = useTheme();
54
+ const getFormattedDate = useDateLookup({
55
+ getMarker,
56
+ formatDate,
57
+ selectedPeriod
58
+ });
59
+ const paddingHorizontalStyle = useMemo(() => {
60
+ const localStyle = {};
61
+ if (timePeriodGutter) {
62
+ localStyle.paddingHorizontal = theme.space[timePeriodGutter];
63
+ }
64
+ return localStyle;
65
+ }, [theme.space, timePeriodGutter]);
66
+ const rootStyle = useMemo(() => {
67
+ return _extends({}, styles.wrapper, {
68
+ opacity: markerOpacity,
69
+ backgroundColor: theme.color.bg
70
+ }, paddingHorizontalStyle);
71
+ }, [markerOpacity, paddingHorizontalStyle, theme.color.bg]);
72
+ return /*#__PURE__*/_jsx(Animated.View, {
73
+ pointerEvents: "none",
74
+ style: rootStyle,
75
+ children: times(numberOfLabels).map((_, i) => {
76
+ return /*#__PURE__*/_jsx(SparklineInteractiveMarkerDate, {
77
+ getFormattedDate: getFormattedDate
78
+ }, i);
79
+ })
80
+ });
81
+ }
82
+ export const SparklineInteractiveMarkerDates = /*#__PURE__*/memo(SparklineInteractiveMarkerDatesWithGeneric);
@@ -0,0 +1,103 @@
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, { memo, useCallback, useMemo, useRef } from 'react';
3
+ import { Animated, StyleSheet } from 'react-native';
4
+ import { useLayout } from '@coinbase/cds-mobile/hooks/useLayout';
5
+ import { useTheme } from '@coinbase/cds-mobile/hooks/useTheme';
6
+ import { TextLabel2 } from '@coinbase/cds-mobile/typography';
7
+ import { useSparklineInteractiveContext } from './SparklineInteractiveProvider';
8
+ import { useMinMaxTransform } from './useMinMaxTransform';
9
+ import { useSparklineInteractiveConstants } from './useSparklineInteractiveConstants';
10
+ import { jsx as _jsx } from "react/jsx-runtime";
11
+ const styles = StyleSheet.create({
12
+ outer: {
13
+ width: '100%',
14
+ alignItems: 'center'
15
+ },
16
+ caption: {
17
+ position: 'absolute',
18
+ left: 0,
19
+ top: 0
20
+ }
21
+ });
22
+ const SparklineInteractiveMinMaxContent = /*#__PURE__*/memo(_ref => {
23
+ let {
24
+ x,
25
+ children
26
+ } = _ref;
27
+ const theme = useTheme();
28
+ const [minMaxLayout, onMinMaxLayout] = useLayout();
29
+ const opacity = useRef(new Animated.Value(0)).current;
30
+ const transform = useRef(new Animated.ValueXY({
31
+ x: 0,
32
+ y: 0
33
+ })).current;
34
+ useMinMaxTransform({
35
+ minMaxLayout,
36
+ x,
37
+ transform,
38
+ opacity
39
+ });
40
+
41
+ // Only do the layout if there is a new child.
42
+ // This prevents jitter in the case where children is
43
+ // set to undefined, then returned to the previous value,
44
+ // as is the case for privacy mode (where we hide the value)
45
+ const onLayout = useCallback(event => {
46
+ if (!children) {
47
+ return;
48
+ }
49
+ return onMinMaxLayout(event);
50
+ }, [onMinMaxLayout, children]);
51
+ const rootStyle = useMemo(() => {
52
+ return _extends({}, styles.caption, {
53
+ height: theme.lineHeight.label2,
54
+ opacity,
55
+ transform: transform.getTranslateTransform()
56
+ });
57
+ }, [opacity, theme.lineHeight.label2, transform]);
58
+ const textLabelStyle = useMemo(() => {
59
+ return _extends({}, styles.caption, {
60
+ backgroundColor: theme.color.bg
61
+ });
62
+ }, [theme.color.bg]);
63
+ return /*#__PURE__*/_jsx(Animated.View, {
64
+ pointerEvents: "none",
65
+ style: rootStyle,
66
+ children: /*#__PURE__*/_jsx(TextLabel2, {
67
+ color: "fgMuted",
68
+ onLayout: onLayout,
69
+ padding: 0,
70
+ style: textLabelStyle,
71
+ children: children
72
+ })
73
+ });
74
+ });
75
+ export const SparklineInteractiveMinMax = /*#__PURE__*/memo(_ref2 => {
76
+ let {
77
+ formatMinMaxLabel,
78
+ dataPoint,
79
+ xFunction
80
+ } = _ref2;
81
+ const theme = useTheme();
82
+ const {
83
+ minMaxOpacity
84
+ } = useSparklineInteractiveContext();
85
+ const {
86
+ SparklineInteractiveMinMaxLabelHeight
87
+ } = useSparklineInteractiveConstants({});
88
+ const rootStyle = useMemo(() => {
89
+ return _extends({}, styles.outer, {
90
+ opacity: minMaxOpacity,
91
+ backgroundColor: theme.color.bg,
92
+ height: SparklineInteractiveMinMaxLabelHeight
93
+ });
94
+ }, [SparklineInteractiveMinMaxLabelHeight, minMaxOpacity, theme.color.bg]);
95
+ return /*#__PURE__*/_jsx(Animated.View, {
96
+ pointerEvents: "none",
97
+ style: rootStyle,
98
+ children: !!dataPoint && /*#__PURE__*/_jsx(SparklineInteractiveMinMaxContent, {
99
+ x: xFunction(dataPoint.date),
100
+ children: formatMinMaxLabel(dataPoint.value)
101
+ })
102
+ });
103
+ });
@@ -0,0 +1,104 @@
1
+ import React, { useCallback } from 'react';
2
+ import { Animated as RNAnimated, Platform, View } from 'react-native';
3
+ import { Gesture, GestureDetector } from 'react-native-gesture-handler';
4
+ import Animated, { runOnJS } from 'react-native-reanimated';
5
+ import { Haptics } from '@coinbase/cds-mobile/utils/haptics';
6
+ import { noop } from '@coinbase/cds-utils';
7
+ import { useSparklineInteractiveContext } from './SparklineInteractiveProvider';
8
+ import { useSparklineInteractiveConstants } from './useSparklineInteractiveConstants';
9
+ import { jsx as _jsx } from "react/jsx-runtime";
10
+ const {
11
+ lightImpact
12
+ } = Haptics;
13
+ // Generics do not work with React.memo or forwardRef
14
+ // https://stackoverflow.com/questions/58469229/react-with-typescript-generics-while-using-react-forwardref/58473012
15
+ export const SparklineInteractivePanGestureHandler = function SparklineInteractivePanGestureHandler(_ref) {
16
+ let {
17
+ onScrubEnd = noop,
18
+ onScrubStart = noop,
19
+ onScrub = noop,
20
+ getMarker,
21
+ selectedPeriod,
22
+ children,
23
+ disabled,
24
+ allowOverflowGestures
25
+ } = _ref;
26
+ const {
27
+ markerXPosition,
28
+ markerGestureState,
29
+ animateMarkerIn,
30
+ animateMarkerOut,
31
+ animateMinMaxIn,
32
+ animateMinxMaxOut,
33
+ animateHoverDateIn,
34
+ animateHoverDateOut
35
+ } = useSparklineInteractiveContext();
36
+ const {
37
+ chartVerticalLineWidth,
38
+ endX,
39
+ startX
40
+ } = useSparklineInteractiveConstants({});
41
+ const handleOnStartJsThread = useCallback(() => {
42
+ void lightImpact();
43
+ onScrubStart();
44
+ RNAnimated.parallel([animateMarkerIn, animateMinxMaxOut, animateHoverDateIn]).start();
45
+ }, [animateHoverDateIn, animateMarkerIn, animateMinxMaxOut, onScrubStart]);
46
+ const handleOnUpdateJsThread = useCallback(() => {
47
+ const dataPoint = getMarker(markerXPosition.value);
48
+ if (dataPoint) {
49
+ onScrub({
50
+ point: dataPoint,
51
+ period: selectedPeriod
52
+ });
53
+ }
54
+ }, [getMarker, markerXPosition.value, onScrub, selectedPeriod]);
55
+ const handleOnEndOrCancelledJsThread = useCallback(() => {
56
+ onScrubEnd();
57
+ RNAnimated.parallel([animateMarkerOut, animateMinMaxIn, animateHoverDateOut]).start(_ref2 => {
58
+ let {
59
+ finished
60
+ } = _ref2;
61
+ if (finished) {
62
+ markerXPosition.value = -1;
63
+ }
64
+ });
65
+ }, [animateHoverDateOut, animateMarkerOut, animateMinMaxIn, markerXPosition, onScrubEnd]);
66
+ const handleOnEndJsThread = useCallback(() => {
67
+ void Haptics.lightImpact();
68
+ handleOnEndOrCancelledJsThread();
69
+ }, [handleOnEndOrCancelledJsThread]);
70
+ if (disabled) {
71
+ return /*#__PURE__*/_jsx(View, {
72
+ children: children
73
+ });
74
+ }
75
+ const longPressGesture = Gesture.Pan().activateAfterLongPress(110).shouldCancelWhenOutside(!allowOverflowGestures).onStart(function onStart(event) {
76
+ runOnJS(handleOnStartJsThread)();
77
+ markerGestureState.value = 1;
78
+
79
+ // Android does not trigger onUpdate when the gesture starts. This achieves consistent behavior across both iOS and Android
80
+ if (Platform.OS === 'android') {
81
+ const newMarkerXPosition = Math.min(endX, Math.max(startX, event.x - chartVerticalLineWidth / 2));
82
+ markerXPosition.value = newMarkerXPosition;
83
+ runOnJS(handleOnUpdateJsThread)();
84
+ }
85
+ }).onUpdate(function onUpdate(event) {
86
+ const newMarkerXPosition = Math.min(endX, Math.max(startX, event.x - chartVerticalLineWidth / 2));
87
+ markerXPosition.value = newMarkerXPosition;
88
+ if (markerGestureState.value === 1) {
89
+ runOnJS(handleOnUpdateJsThread)();
90
+ }
91
+ }).onEnd(function onEnd() {
92
+ markerGestureState.value = 0;
93
+ runOnJS(handleOnEndJsThread)();
94
+ }).onTouchesCancelled(function onTouchesCancelled() {
95
+ markerGestureState.value = 0;
96
+ runOnJS(handleOnEndOrCancelledJsThread)();
97
+ });
98
+ return /*#__PURE__*/_jsx(GestureDetector, {
99
+ gesture: longPressGesture,
100
+ children: /*#__PURE__*/_jsx(Animated.View, {
101
+ children: children
102
+ })
103
+ });
104
+ };
@@ -0,0 +1,53 @@
1
+ import React, { memo, useCallback, useRef } from 'react';
2
+ import { SparklineInteractiveAnimatedPath } from './SparklineInteractiveAnimatedPath';
3
+ import { SparklineInteractiveTimeseriesPaths } from './SparklineInteractiveTimeseriesPaths';
4
+ import { useSparklineInteractiveConstants } from './useSparklineInteractiveConstants';
5
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
6
+ function SparklineInteractivePathsWithGeneric(_ref) {
7
+ let {
8
+ showHoverData,
9
+ fill,
10
+ path,
11
+ area,
12
+ selectedPeriod,
13
+ yAxisScalingFactor,
14
+ strokeColor,
15
+ hoverData,
16
+ compact
17
+ } = _ref;
18
+ const hoverPathRef = useRef(undefined);
19
+ const hoverAreaRef = useRef(undefined);
20
+ const shouldShowFill = !!fill;
21
+ const {
22
+ chartWidth,
23
+ chartHeight
24
+ } = useSparklineInteractiveConstants({
25
+ compact
26
+ });
27
+ const handleMultiTimeseriesRender = useCallback(_ref2 => {
28
+ let {
29
+ area: timeseriesArea,
30
+ path: timeseriesPath
31
+ } = _ref2;
32
+ hoverPathRef.current = timeseriesPath;
33
+ hoverAreaRef.current = timeseriesArea;
34
+ }, []);
35
+ return /*#__PURE__*/_jsxs(_Fragment, {
36
+ children: [!showHoverData && /*#__PURE__*/_jsx(SparklineInteractiveAnimatedPath, {
37
+ area: shouldShowFill ? area : undefined,
38
+ color: strokeColor,
39
+ d: path,
40
+ initialArea: hoverAreaRef.current,
41
+ initialPath: hoverPathRef.current,
42
+ selectedPeriod: selectedPeriod,
43
+ yAxisScalingFactor: yAxisScalingFactor
44
+ }), !!showHoverData && /*#__PURE__*/_jsx(SparklineInteractiveTimeseriesPaths, {
45
+ data: hoverData == null ? void 0 : hoverData[selectedPeriod],
46
+ height: chartHeight,
47
+ initialPath: path,
48
+ onRender: handleMultiTimeseriesRender,
49
+ width: chartWidth
50
+ })]
51
+ });
52
+ }
53
+ export const SparklineInteractivePaths = /*#__PURE__*/memo(SparklineInteractivePathsWithGeneric);