@coinbase/cds-mobile-visualization 3.4.0-beta.2 → 3.4.0-beta.21

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 (211) hide show
  1. package/CHANGELOG.md +128 -0
  2. package/dts/chart/CartesianChart.d.ts +92 -34
  3. package/dts/chart/CartesianChart.d.ts.map +1 -1
  4. package/dts/chart/ChartContextBridge.d.ts +28 -0
  5. package/dts/chart/ChartContextBridge.d.ts.map +1 -0
  6. package/dts/chart/ChartProvider.d.ts +3 -0
  7. package/dts/chart/ChartProvider.d.ts.map +1 -1
  8. package/dts/chart/Path.d.ts +97 -32
  9. package/dts/chart/Path.d.ts.map +1 -1
  10. package/dts/chart/PeriodSelector.d.ts +6 -13
  11. package/dts/chart/PeriodSelector.d.ts.map +1 -1
  12. package/dts/chart/area/Area.d.ts +39 -28
  13. package/dts/chart/area/Area.d.ts.map +1 -1
  14. package/dts/chart/area/AreaChart.d.ts +51 -10
  15. package/dts/chart/area/AreaChart.d.ts.map +1 -1
  16. package/dts/chart/area/DottedArea.d.ts +21 -2
  17. package/dts/chart/area/DottedArea.d.ts.map +1 -1
  18. package/dts/chart/area/GradientArea.d.ts +19 -13
  19. package/dts/chart/area/GradientArea.d.ts.map +1 -1
  20. package/dts/chart/area/SolidArea.d.ts +17 -2
  21. package/dts/chart/area/SolidArea.d.ts.map +1 -1
  22. package/dts/chart/axis/Axis.d.ts +86 -118
  23. package/dts/chart/axis/Axis.d.ts.map +1 -1
  24. package/dts/chart/axis/DefaultAxisTickLabel.d.ts +8 -0
  25. package/dts/chart/axis/DefaultAxisTickLabel.d.ts.map +1 -0
  26. package/dts/chart/axis/XAxis.d.ts +1 -1
  27. package/dts/chart/axis/XAxis.d.ts.map +1 -1
  28. package/dts/chart/axis/YAxis.d.ts +2 -2
  29. package/dts/chart/axis/YAxis.d.ts.map +1 -1
  30. package/dts/chart/axis/index.d.ts +1 -0
  31. package/dts/chart/axis/index.d.ts.map +1 -1
  32. package/dts/chart/bar/Bar.d.ts +49 -12
  33. package/dts/chart/bar/Bar.d.ts.map +1 -1
  34. package/dts/chart/bar/BarChart.d.ts +40 -19
  35. package/dts/chart/bar/BarChart.d.ts.map +1 -1
  36. package/dts/chart/bar/BarPlot.d.ts +3 -1
  37. package/dts/chart/bar/BarPlot.d.ts.map +1 -1
  38. package/dts/chart/bar/BarStack.d.ts +41 -46
  39. package/dts/chart/bar/BarStack.d.ts.map +1 -1
  40. package/dts/chart/bar/BarStackGroup.d.ts +2 -0
  41. package/dts/chart/bar/BarStackGroup.d.ts.map +1 -1
  42. package/dts/chart/bar/DefaultBar.d.ts +1 -1
  43. package/dts/chart/bar/DefaultBar.d.ts.map +1 -1
  44. package/dts/chart/bar/DefaultBarStack.d.ts.map +1 -1
  45. package/dts/chart/gradient/Gradient.d.ts +25 -0
  46. package/dts/chart/gradient/Gradient.d.ts.map +1 -0
  47. package/dts/chart/gradient/index.d.ts +2 -0
  48. package/dts/chart/gradient/index.d.ts.map +1 -0
  49. package/dts/chart/index.d.ts +4 -1
  50. package/dts/chart/index.d.ts.map +1 -1
  51. package/dts/chart/legend/DefaultLegendEntry.d.ts +5 -0
  52. package/dts/chart/legend/DefaultLegendEntry.d.ts.map +1 -0
  53. package/dts/chart/legend/DefaultLegendShape.d.ts +5 -0
  54. package/dts/chart/legend/DefaultLegendShape.d.ts.map +1 -0
  55. package/dts/chart/legend/Legend.d.ts +168 -0
  56. package/dts/chart/legend/Legend.d.ts.map +1 -0
  57. package/dts/chart/legend/index.d.ts +4 -0
  58. package/dts/chart/legend/index.d.ts.map +1 -0
  59. package/dts/chart/line/DefaultReferenceLineLabel.d.ts +9 -0
  60. package/dts/chart/line/DefaultReferenceLineLabel.d.ts.map +1 -0
  61. package/dts/chart/line/DottedLine.d.ts +13 -5
  62. package/dts/chart/line/DottedLine.d.ts.map +1 -1
  63. package/dts/chart/line/Line.d.ts +61 -27
  64. package/dts/chart/line/Line.d.ts.map +1 -1
  65. package/dts/chart/line/LineChart.d.ts +43 -9
  66. package/dts/chart/line/LineChart.d.ts.map +1 -1
  67. package/dts/chart/line/ReferenceLine.d.ts +68 -20
  68. package/dts/chart/line/ReferenceLine.d.ts.map +1 -1
  69. package/dts/chart/line/SolidLine.d.ts +8 -5
  70. package/dts/chart/line/SolidLine.d.ts.map +1 -1
  71. package/dts/chart/line/index.d.ts +1 -1
  72. package/dts/chart/line/index.d.ts.map +1 -1
  73. package/dts/chart/point/DefaultPointLabel.d.ts +10 -0
  74. package/dts/chart/point/DefaultPointLabel.d.ts.map +1 -0
  75. package/dts/chart/point/Point.d.ts +136 -0
  76. package/dts/chart/point/Point.d.ts.map +1 -0
  77. package/dts/chart/point/index.d.ts +3 -0
  78. package/dts/chart/point/index.d.ts.map +1 -0
  79. package/dts/chart/scrubber/DefaultScrubberBeacon.d.ts +38 -0
  80. package/dts/chart/scrubber/DefaultScrubberBeacon.d.ts.map +1 -0
  81. package/dts/chart/scrubber/DefaultScrubberBeaconLabel.d.ts +12 -0
  82. package/dts/chart/scrubber/DefaultScrubberBeaconLabel.d.ts.map +1 -0
  83. package/dts/chart/scrubber/DefaultScrubberLabel.d.ts +11 -0
  84. package/dts/chart/scrubber/DefaultScrubberLabel.d.ts.map +1 -0
  85. package/dts/chart/scrubber/Scrubber.d.ts +230 -42
  86. package/dts/chart/scrubber/Scrubber.d.ts.map +1 -1
  87. package/dts/chart/scrubber/ScrubberBeaconGroup.d.ts +54 -0
  88. package/dts/chart/scrubber/ScrubberBeaconGroup.d.ts.map +1 -0
  89. package/dts/chart/scrubber/ScrubberBeaconLabelGroup.d.ts +46 -0
  90. package/dts/chart/scrubber/ScrubberBeaconLabelGroup.d.ts.map +1 -0
  91. package/dts/chart/scrubber/ScrubberProvider.d.ts +6 -3
  92. package/dts/chart/scrubber/ScrubberProvider.d.ts.map +1 -1
  93. package/dts/chart/scrubber/index.d.ts +3 -0
  94. package/dts/chart/scrubber/index.d.ts.map +1 -1
  95. package/dts/chart/text/ChartText.d.ts +151 -77
  96. package/dts/chart/text/ChartText.d.ts.map +1 -1
  97. package/dts/chart/text/{SmartChartTextGroup.d.ts → ChartTextGroup.d.ts} +9 -3
  98. package/dts/chart/text/ChartTextGroup.d.ts.map +1 -0
  99. package/dts/chart/text/index.d.ts +1 -1
  100. package/dts/chart/text/index.d.ts.map +1 -1
  101. package/dts/chart/utils/axis.d.ts +25 -1
  102. package/dts/chart/utils/axis.d.ts.map +1 -1
  103. package/dts/chart/utils/bar.d.ts +34 -0
  104. package/dts/chart/utils/bar.d.ts.map +1 -1
  105. package/dts/chart/utils/chart.d.ts +52 -7
  106. package/dts/chart/utils/chart.d.ts.map +1 -1
  107. package/dts/chart/utils/context.d.ts +28 -7
  108. package/dts/chart/utils/context.d.ts.map +1 -1
  109. package/dts/chart/utils/gradient.d.ts +117 -0
  110. package/dts/chart/utils/gradient.d.ts.map +1 -0
  111. package/dts/chart/utils/index.d.ts +3 -0
  112. package/dts/chart/utils/index.d.ts.map +1 -1
  113. package/dts/chart/utils/path.d.ts +59 -0
  114. package/dts/chart/utils/path.d.ts.map +1 -1
  115. package/dts/chart/utils/point.d.ts +71 -7
  116. package/dts/chart/utils/point.d.ts.map +1 -1
  117. package/dts/chart/utils/scale.d.ts +102 -0
  118. package/dts/chart/utils/scale.d.ts.map +1 -1
  119. package/dts/chart/utils/scrubber.d.ts +40 -0
  120. package/dts/chart/utils/scrubber.d.ts.map +1 -0
  121. package/dts/chart/utils/transition.d.ts +178 -0
  122. package/dts/chart/utils/transition.d.ts.map +1 -0
  123. package/esm/chart/CartesianChart.js +199 -75
  124. package/esm/chart/ChartContextBridge.js +159 -0
  125. package/esm/chart/ChartProvider.js +2 -2
  126. package/esm/chart/Path.js +200 -114
  127. package/esm/chart/PeriodSelector.js +7 -3
  128. package/esm/chart/__stories__/CartesianChart.stories.js +307 -134
  129. package/esm/chart/__stories__/ChartTransitions.stories.js +629 -0
  130. package/esm/chart/__stories__/PeriodSelector.stories.js +201 -75
  131. package/esm/chart/area/Area.js +27 -35
  132. package/esm/chart/area/AreaChart.js +17 -12
  133. package/esm/chart/area/DottedArea.js +64 -108
  134. package/esm/chart/area/GradientArea.js +37 -91
  135. package/esm/chart/area/SolidArea.js +24 -8
  136. package/esm/chart/area/__stories__/AreaChart.stories.js +1 -1
  137. package/esm/chart/axis/Axis.js +5 -39
  138. package/esm/chart/axis/DefaultAxisTickLabel.js +11 -0
  139. package/esm/chart/axis/XAxis.js +148 -66
  140. package/esm/chart/axis/YAxis.js +149 -65
  141. package/esm/chart/axis/__stories__/Axis.stories.js +259 -1
  142. package/esm/chart/axis/index.js +1 -0
  143. package/esm/chart/bar/Bar.js +7 -1
  144. package/esm/chart/bar/BarChart.js +17 -37
  145. package/esm/chart/bar/BarPlot.js +43 -35
  146. package/esm/chart/bar/BarStack.js +84 -37
  147. package/esm/chart/bar/BarStackGroup.js +7 -17
  148. package/esm/chart/bar/DefaultBar.js +29 -51
  149. package/esm/chart/bar/DefaultBarStack.js +34 -58
  150. package/esm/chart/bar/__stories__/BarChart.stories.js +948 -88
  151. package/esm/chart/gradient/Gradient.js +53 -0
  152. package/esm/chart/gradient/index.js +1 -0
  153. package/esm/chart/index.js +4 -1
  154. package/esm/chart/legend/DefaultLegendEntry.js +42 -0
  155. package/esm/chart/legend/DefaultLegendShape.js +64 -0
  156. package/esm/chart/legend/Legend.js +59 -0
  157. package/esm/chart/legend/__stories__/Legend.stories.js +574 -0
  158. package/esm/chart/legend/index.js +3 -0
  159. package/esm/chart/line/DefaultReferenceLineLabel.js +66 -0
  160. package/esm/chart/line/DottedLine.js +31 -14
  161. package/esm/chart/line/Line.js +96 -68
  162. package/esm/chart/line/LineChart.js +21 -14
  163. package/esm/chart/line/ReferenceLine.js +80 -63
  164. package/esm/chart/line/SolidLine.js +27 -10
  165. package/esm/chart/line/__stories__/LineChart.stories.js +1748 -2048
  166. package/esm/chart/line/__stories__/ReferenceLine.stories.js +177 -28
  167. package/esm/chart/line/index.js +1 -1
  168. package/esm/chart/point/DefaultPointLabel.js +39 -0
  169. package/esm/chart/point/Point.js +186 -0
  170. package/esm/chart/point/index.js +2 -0
  171. package/esm/chart/scrubber/DefaultScrubberBeacon.js +180 -0
  172. package/esm/chart/scrubber/DefaultScrubberBeaconLabel.js +43 -0
  173. package/esm/chart/scrubber/DefaultScrubberLabel.js +28 -0
  174. package/esm/chart/scrubber/Scrubber.js +130 -144
  175. package/esm/chart/scrubber/ScrubberBeaconGroup.js +165 -0
  176. package/esm/chart/scrubber/ScrubberBeaconLabelGroup.js +208 -0
  177. package/esm/chart/scrubber/ScrubberProvider.js +46 -54
  178. package/esm/chart/scrubber/__stories__/Scrubber.stories.js +760 -0
  179. package/esm/chart/scrubber/index.js +3 -1
  180. package/esm/chart/text/ChartText.js +242 -174
  181. package/esm/chart/text/{SmartChartTextGroup.js → ChartTextGroup.js} +6 -5
  182. package/esm/chart/text/index.js +1 -1
  183. package/esm/chart/utils/axis.js +47 -31
  184. package/esm/chart/utils/bar.js +43 -0
  185. package/esm/chart/utils/chart.js +57 -3
  186. package/esm/chart/utils/gradient.js +305 -0
  187. package/esm/chart/utils/index.js +3 -0
  188. package/esm/chart/utils/path.js +84 -8
  189. package/esm/chart/utils/point.js +171 -17
  190. package/esm/chart/utils/scale.js +242 -2
  191. package/esm/chart/utils/scrubber.js +146 -0
  192. package/esm/chart/utils/transition.js +215 -0
  193. package/esm/sparkline/__figma__/Sparkline.figma.js +1 -1
  194. package/esm/sparkline/__stories__/Sparkline.stories.js +11 -7
  195. package/esm/sparkline/__stories__/SparklineGradient.stories.js +7 -4
  196. package/esm/sparkline/sparkline-interactive/__figma__/SparklineInteractive.figma.js +1 -1
  197. package/esm/sparkline/sparkline-interactive/__stories__/SparklineInteractive.stories.js +51 -26
  198. package/esm/sparkline/sparkline-interactive-header/__figma__/SparklineInteractiveHeader.figma.js +1 -1
  199. package/esm/sparkline/sparkline-interactive-header/__stories__/SparklineInteractiveHeader.stories.js +17 -9
  200. package/package.json +15 -10
  201. package/dts/chart/Point.d.ts +0 -103
  202. package/dts/chart/Point.d.ts.map +0 -1
  203. package/dts/chart/line/GradientLine.d.ts +0 -45
  204. package/dts/chart/line/GradientLine.d.ts.map +0 -1
  205. package/dts/chart/scrubber/ScrubberBeacon.d.ts +0 -75
  206. package/dts/chart/scrubber/ScrubberBeacon.d.ts.map +0 -1
  207. package/dts/chart/text/SmartChartTextGroup.d.ts.map +0 -1
  208. package/esm/chart/Point.js +0 -111
  209. package/esm/chart/__stories__/Chart.stories.js +0 -79
  210. package/esm/chart/line/GradientLine.js +0 -62
  211. package/esm/chart/scrubber/ScrubberBeacon.js +0 -199
@@ -0,0 +1,43 @@
1
+ const _excluded = ["background", "color", "elevated", "borderRadius", "font", "verticalAlignment", "inset", "label"];
2
+ function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
3
+ function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
4
+ import { memo } from 'react';
5
+ import { useTheme } from '@coinbase/cds-mobile';
6
+ import { ChartText } from '../text';
7
+ import { jsx as _jsx } from "react/jsx-runtime";
8
+ const labelVerticalInset = 3.5;
9
+ const labelHorizontalInset = 4;
10
+ /**
11
+ * DefaultScrubberBeaconLabel is a special instance of ChartText used to label a series' scrubber beacon.
12
+ */
13
+ export const DefaultScrubberBeaconLabel = /*#__PURE__*/memo(_ref => {
14
+ let {
15
+ background,
16
+ color,
17
+ elevated = true,
18
+ borderRadius = 4,
19
+ font = 'label1',
20
+ verticalAlignment = 'middle',
21
+ inset = {
22
+ left: labelHorizontalInset,
23
+ right: labelHorizontalInset,
24
+ top: labelVerticalInset,
25
+ bottom: labelVerticalInset
26
+ },
27
+ label
28
+ } = _ref,
29
+ chartTextProps = _objectWithoutPropertiesLoose(_ref, _excluded);
30
+ const theme = useTheme();
31
+ return /*#__PURE__*/_jsx(ChartText, _extends({
32
+ disableRepositioning: true,
33
+ background: background != null ? background : theme.color.bg,
34
+ borderRadius: borderRadius,
35
+ color: color != null ? color : theme.color.fgPrimary,
36
+ elevated: elevated,
37
+ font: font,
38
+ inset: inset,
39
+ verticalAlignment: verticalAlignment
40
+ }, chartTextProps, {
41
+ children: label
42
+ }));
43
+ });
@@ -0,0 +1,28 @@
1
+ const _excluded = ["verticalAlignment", "dy", "boundsInset"];
2
+ function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
3
+ function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
4
+ import { memo } from 'react';
5
+ import { useCartesianChartContext } from '../ChartProvider';
6
+ import { DefaultReferenceLineLabel } from '../line';
7
+ import { jsx as _jsx } from "react/jsx-runtime";
8
+ /**
9
+ * DefaultScrubberLabel is the default label component for the scrubber line.
10
+ * It will automatically add padding around the label when elevated to fit within chart bounds to prevent shadow from being cutoff.
11
+ * It will also center the label vertically with the top available area.
12
+ */
13
+ export const DefaultScrubberLabel = /*#__PURE__*/memo(_ref => {
14
+ let {
15
+ verticalAlignment = 'middle',
16
+ dy,
17
+ boundsInset
18
+ } = _ref,
19
+ props = _objectWithoutPropertiesLoose(_ref, _excluded);
20
+ const {
21
+ drawingArea
22
+ } = useCartesianChartContext();
23
+ return /*#__PURE__*/_jsx(DefaultReferenceLineLabel, _extends({
24
+ boundsInset: boundsInset,
25
+ dy: dy != null ? dy : -0.5 * drawingArea.y,
26
+ verticalAlignment: verticalAlignment
27
+ }, props));
28
+ });
@@ -1,186 +1,172 @@
1
- import React, { forwardRef, memo, useCallback, useEffect, useImperativeHandle, useMemo, useRef } from 'react';
2
- import { Animated } from 'react-native';
3
- import { useAnimatedProps, useSharedValue } from 'react-native-reanimated';
4
- import { G, Rect } from 'react-native-svg';
5
- import { useRefMap } from '@coinbase/cds-common/hooks/useRefMap';
1
+ import React, { forwardRef, memo, useCallback, useEffect, useImperativeHandle, useMemo } from 'react';
2
+ import { runOnJS, useAnimatedReaction, useDerivedValue, useSharedValue } from 'react-native-reanimated';
6
3
  import { useTheme } from '@coinbase/cds-mobile';
4
+ import { Group, Rect } from '@shopify/react-native-skia';
7
5
  import { useCartesianChartContext } from '../ChartProvider';
8
6
  import { ReferenceLine } from '../line';
9
- import { useScrubberContext } from '../utils';
10
- import { ScrubberBeacon } from './ScrubberBeacon';
11
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
12
- const AnimatedRect = Animated.createAnimatedComponent(Rect);
13
-
14
- /**
15
- * Configuration for scrubber functionality across chart components.
16
- * Provides consistent API with smart defaults and component customization.
17
- */
18
-
7
+ import { defaultAccessoryEnterTransition, getPointOnSerializableScale, getTransition, useScrubberContext } from '../utils';
8
+ import { buildTransition } from '../utils/transition';
9
+ import { DefaultScrubberBeacon } from './DefaultScrubberBeacon';
10
+ import { DefaultScrubberLabel } from './DefaultScrubberLabel';
11
+ import { ScrubberBeaconGroup } from './ScrubberBeaconGroup';
12
+ import { ScrubberBeaconLabelGroup } from './ScrubberBeaconLabelGroup';
13
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
19
14
  /**
20
- * Unified component that manages all scrubber elements (beacons, line, labels)
21
- * with intelligent collision detection and consistent positioning.
15
+ * Unified component that manages all scrubber elements (beacons, line, labels).
22
16
  */
23
17
  export const Scrubber = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) => {
24
18
  let {
25
19
  seriesIds,
20
+ hideBeaconLabels,
26
21
  hideLine,
27
22
  label,
28
23
  lineStroke,
29
- labelProps,
30
- BeaconComponent = ScrubberBeacon,
31
- LineComponent = ReferenceLine,
24
+ BeaconComponent = DefaultScrubberBeacon,
25
+ BeaconLabelComponent,
26
+ LineComponent,
27
+ LabelComponent = DefaultScrubberLabel,
28
+ labelElevated,
32
29
  hideOverlay,
33
30
  overlayOffset = 2,
34
- testID,
35
- idlePulse
31
+ beaconLabelMinGap,
32
+ beaconLabelHorizontalOffset,
33
+ beaconLabelPreferredSide,
34
+ labelFont,
35
+ labelBoundsInset,
36
+ beaconLabelFont,
37
+ idlePulse,
38
+ beaconTransitions,
39
+ transitions = beaconTransitions,
40
+ beaconStroke
36
41
  } = _ref;
37
42
  const theme = useTheme();
38
- const ScrubberBeaconRefs = useRefMap();
39
-
40
- // Animated values for overlay positions (using react-native Animated)
41
- const overlayX = useRef(new Animated.Value(0)).current;
42
- const overlayWidth = useRef(new Animated.Value(0)).current;
43
-
44
- // Reanimated shared value for scrubber line
45
- const scrubberLineX = useSharedValue(0);
43
+ const beaconGroupRef = React.useRef(null);
46
44
  const {
47
- scrubberPosition: scrubberPosition
45
+ scrubberPosition
48
46
  } = useScrubberContext();
49
47
  const {
50
- getXScale,
51
- getYScale,
52
- getSeriesData,
48
+ getXSerializableScale,
53
49
  getXAxis,
54
50
  series,
55
- drawingArea
51
+ drawingArea,
52
+ animate,
53
+ dataLength
56
54
  } = useCartesianChartContext();
57
- const getStackedSeriesData = getSeriesData; // getSeriesData now returns stacked data
55
+ const xAxis = useMemo(() => getXAxis(), [getXAxis]);
56
+ const xScale = useMemo(() => getXSerializableScale(), [getXSerializableScale]);
58
57
 
59
- // Animated props for scrubber line
60
- const scrubberLineAnimatedProps = useAnimatedProps(() => ({
61
- x1: scrubberLineX.value,
62
- x2: scrubberLineX.value
63
- }));
58
+ // Animation state for delayed scrubber rendering (matches web timing)
59
+ const scrubberOpacity = useSharedValue(animate ? 0 : 1);
64
60
 
65
61
  // Expose imperative handle with pulse method
66
62
  useImperativeHandle(ref, () => ({
67
63
  pulse: () => {
68
- // Pulse all registered scrubber beacons
69
- Object.values(ScrubberBeaconRefs.refs).forEach(beaconRef => {
70
- beaconRef == null || beaconRef.pulse();
71
- });
64
+ var _beaconGroupRef$curre;
65
+ (_beaconGroupRef$curre = beaconGroupRef.current) == null || _beaconGroupRef$curre.pulse();
72
66
  }
73
67
  }));
74
- const {
75
- dataX,
76
- dataIndex
77
- } = useMemo(() => {
78
- var _series$reduce;
79
- const xScale = getXScale();
80
- const xAxis = getXAxis();
81
- if (!xScale) return {
82
- dataX: undefined,
83
- dataIndex: undefined
84
- };
85
- const maxDataLength = (_series$reduce = series == null ? void 0 : series.reduce((max, s) => {
86
- var _seriesData$length;
87
- const seriesData = getStackedSeriesData(s.id) || getSeriesData(s.id);
88
- return Math.max(max, (_seriesData$length = seriesData == null ? void 0 : seriesData.length) != null ? _seriesData$length : 0);
89
- }, 0)) != null ? _series$reduce : 0;
90
- const dataIndex = scrubberPosition != null ? scrubberPosition : Math.max(0, maxDataLength - 1);
91
-
92
- // Convert index to actual x value if axis has data
93
- let dataX;
94
- if (xAxis != null && xAxis.data && Array.isArray(xAxis.data) && xAxis.data[dataIndex] !== undefined) {
95
- const dataValue = xAxis.data[dataIndex];
96
- dataX = typeof dataValue === 'string' ? dataIndex : dataValue;
97
- } else {
98
- dataX = dataIndex;
68
+ const filteredSeriesIds = useMemo(() => {
69
+ if (seriesIds === undefined) {
70
+ var _series$map;
71
+ return (_series$map = series == null ? void 0 : series.map(s => s.id)) != null ? _series$map : [];
72
+ }
73
+ return seriesIds;
74
+ }, [series, seriesIds]);
75
+ const dataIndex = useDerivedValue(() => {
76
+ var _scrubberPosition$val;
77
+ return (_scrubberPosition$val = scrubberPosition.value) != null ? _scrubberPosition$val : Math.max(0, dataLength - 1);
78
+ }, [scrubberPosition, dataLength]);
79
+ const dataX = useDerivedValue(() => {
80
+ if (xAxis != null && xAxis.data && Array.isArray(xAxis.data) && xAxis.data[dataIndex.value] !== undefined) {
81
+ const dataValue = xAxis.data[dataIndex.value];
82
+ return typeof dataValue === 'string' ? dataIndex.value : dataValue;
83
+ }
84
+ return dataIndex.value;
85
+ }, [xAxis, dataIndex]);
86
+ const lineOpacity = useDerivedValue(() => {
87
+ return scrubberPosition.value !== undefined ? 1 : 0;
88
+ }, [scrubberPosition]);
89
+ const overlayOpacity = useDerivedValue(() => {
90
+ return scrubberPosition.value !== undefined ? 0.8 : 0;
91
+ }, [scrubberPosition]);
92
+ const overlayWidth = useDerivedValue(() => {
93
+ const pixelX = dataX.value !== undefined && xScale ? getPointOnSerializableScale(dataX.value, xScale) : 0;
94
+ return drawingArea.x + drawingArea.width - pixelX + overlayOffset;
95
+ }, [dataX, xScale]);
96
+ const overlayX = useDerivedValue(() => {
97
+ const xValue = dataX.value !== undefined && xScale ? getPointOnSerializableScale(dataX.value, xScale) : 0;
98
+ return xValue;
99
+ }, [dataX, xScale]);
100
+ const resolvedLabelValue = useSharedValue('');
101
+ const updateResolvedLabel = useCallback(index => {
102
+ if (!label) {
103
+ resolvedLabelValue.value = '';
104
+ return;
99
105
  }
100
- return {
101
- dataX,
102
- dataIndex
103
- };
104
- }, [getXScale, getXAxis, series, scrubberPosition, getStackedSeriesData, getSeriesData]);
105
- const beaconPositions = useMemo(() => {
106
- var _series$filter$map$fi, _series$filter;
107
- const xScale = getXScale();
108
- if (!xScale || dataX === undefined || dataIndex === undefined) return [];
109
- return (_series$filter$map$fi = series == null || (_series$filter = series.filter(s => {
110
- if (seriesIds === undefined) return true;
111
- return seriesIds.includes(s.id);
112
- })) == null ? void 0 : _series$filter.map(s => {
113
- const sourceData = getStackedSeriesData(s.id) || getSeriesData(s.id);
114
- // Use dataIndex to get the y value from the series data array
115
- const stuff = sourceData == null ? void 0 : sourceData[dataIndex];
116
- let dataY;
117
- if (Array.isArray(stuff)) {
118
- dataY = stuff[stuff.length - 1];
119
- } else if (typeof stuff === 'number') {
120
- dataY = stuff;
121
- }
122
- if (dataY !== undefined) {
123
- const resolvedLabel = typeof s.label === 'function' ? s.label(dataIndex) : s.label;
124
- return {
125
- x: dataX,
126
- y: dataY,
127
- label: resolvedLabel,
128
- targetSeries: s
129
- };
130
- }
131
- }).filter(beacon => beacon !== undefined)) != null ? _series$filter$map$fi : [];
132
- }, [getXScale, dataX, dataIndex, series, seriesIds, getStackedSeriesData, getSeriesData]);
133
- const createScrubberBeaconRef = useCallback(seriesId => {
134
- return beaconRef => {
135
- if (beaconRef) {
136
- ScrubberBeaconRefs.registerRef(seriesId, beaconRef);
137
- }
138
- };
139
- }, [ScrubberBeaconRefs]);
140
- const defaultXScale = getXScale();
141
- const pixelX = dataX !== undefined && defaultXScale ? defaultXScale(dataX) : undefined;
142
- const memoizedScrubberLabel = useMemo(() => {
143
106
  if (typeof label === 'function') {
144
- if (dataIndex === undefined) return undefined;
145
- return label(dataIndex);
107
+ const result = label(index);
108
+ resolvedLabelValue.value = result != null ? result : '';
109
+ } else if (typeof label === 'string') {
110
+ resolvedLabelValue.value = label;
146
111
  }
147
- return label;
148
- }, [label, dataIndex]);
112
+ }, [label, resolvedLabelValue]);
113
+
114
+ // Update resolved label when dataIndex changes
115
+ useAnimatedReaction(() => dataIndex.value, currentIndex => {
116
+ 'worklet';
117
+
118
+ runOnJS(updateResolvedLabel)(currentIndex);
119
+ }, [updateResolvedLabel]);
120
+ const beaconLabels = useMemo(() => {
121
+ var _series$filter$filter;
122
+ return (_series$filter$filter = series == null ? void 0 : series.filter(s => filteredSeriesIds.includes(s.id)).filter(s => s.label !== undefined && s.label.length > 0).map(s => ({
123
+ seriesId: s.id,
124
+ label: s.label,
125
+ color: s.color
126
+ }))) != null ? _series$filter$filter : [];
127
+ }, [series, filteredSeriesIds]);
128
+ const isReady = !!xScale;
129
+ const groupEnterTransition = useMemo(() => getTransition(transitions == null ? void 0 : transitions.enter, animate, defaultAccessoryEnterTransition), [transitions == null ? void 0 : transitions.enter, animate]);
149
130
  useEffect(() => {
150
- if (pixelX !== undefined) {
151
- scrubberLineX.value = pixelX;
152
- overlayX.setValue(pixelX);
153
- overlayWidth.setValue(drawingArea.x + drawingArea.width - pixelX + overlayOffset);
131
+ if (animate && isReady) {
132
+ scrubberOpacity.value = buildTransition(1, groupEnterTransition);
154
133
  }
155
- }, [pixelX, drawingArea, overlayOffset, scrubberLineX, overlayX, overlayWidth]);
156
- if (!defaultXScale) return null;
157
- return /*#__PURE__*/_jsxs(_Fragment, {
158
- children: [!hideOverlay && dataX !== undefined && scrubberPosition !== undefined && pixelX !== undefined && /*#__PURE__*/_jsx(AnimatedRect, {
159
- fill: theme.color.bg,
134
+ }, [animate, isReady, scrubberOpacity, groupEnterTransition]);
135
+ if (!isReady) return;
136
+ return /*#__PURE__*/_jsxs(Group, {
137
+ opacity: scrubberOpacity,
138
+ children: [!hideOverlay && /*#__PURE__*/_jsx(Rect, {
139
+ color: theme.color.bg,
160
140
  height: drawingArea.height + overlayOffset * 2,
161
- opacity: 0.8,
141
+ opacity: overlayOpacity,
162
142
  width: overlayWidth,
163
143
  x: overlayX,
164
144
  y: drawingArea.y - overlayOffset
165
- }), !hideLine && scrubberPosition !== undefined && dataX !== undefined && /*#__PURE__*/_jsx(LineComponent, {
145
+ }), !hideLine && /*#__PURE__*/_jsx(ReferenceLine, {
146
+ LabelComponent: LabelComponent,
147
+ LineComponent: LineComponent,
166
148
  dataX: dataX,
167
- label: memoizedScrubberLabel,
168
- labelProps: labelProps,
149
+ label: resolvedLabelValue,
150
+ labelBoundsInset: labelBoundsInset,
151
+ labelElevated: labelElevated,
152
+ labelFont: labelFont,
153
+ opacity: lineOpacity,
169
154
  stroke: lineStroke
170
- }), beaconPositions.filter(beacon => beacon !== undefined).map(beacon => {
171
- var _beacon$targetSeries;
172
- return /*#__PURE__*/_jsx(G, {
173
- "data-component": "scrubber-beacon",
174
- children: /*#__PURE__*/_jsx(BeaconComponent, {
175
- ref: createScrubberBeaconRef(beacon.targetSeries.id),
176
- color: (_beacon$targetSeries = beacon.targetSeries) == null ? void 0 : _beacon$targetSeries.color,
177
- dataX: beacon.x,
178
- dataY: beacon.y,
179
- idlePulse: idlePulse,
180
- seriesId: beacon.targetSeries.id,
181
- testID: testID ? testID + "-" + beacon.targetSeries.id + "-dot" : undefined
182
- })
183
- }, beacon.targetSeries.id);
155
+ }), /*#__PURE__*/_jsx(ScrubberBeaconGroup, {
156
+ ref: beaconGroupRef,
157
+ BeaconComponent: BeaconComponent,
158
+ idlePulse: idlePulse,
159
+ seriesIds: filteredSeriesIds,
160
+ stroke: beaconStroke,
161
+ transitions: transitions
162
+ }), !hideBeaconLabels && beaconLabels.length > 0 && /*#__PURE__*/_jsx(ScrubberBeaconLabelGroup, {
163
+ BeaconLabelComponent: BeaconLabelComponent,
164
+ labelFont: beaconLabelFont,
165
+ labelHorizontalOffset: beaconLabelHorizontalOffset,
166
+ labelMinGap: beaconLabelMinGap,
167
+ labelPreferredSide: beaconLabelPreferredSide,
168
+ labels: beaconLabels,
169
+ transitions: transitions
184
170
  })]
185
171
  });
186
172
  }));
@@ -0,0 +1,165 @@
1
+ import { forwardRef, memo, useCallback, useImperativeHandle, useMemo } from 'react';
2
+ import { useDerivedValue } from 'react-native-reanimated';
3
+ import { useRefMap } from '@coinbase/cds-common/hooks/useRefMap';
4
+ import { useTheme } from '@coinbase/cds-mobile';
5
+ import { useCartesianChartContext } from '../ChartProvider';
6
+ import { evaluateGradientAtValue, getGradientStops, useScrubberContext } from '../utils';
7
+ import { convertToSerializableScale } from '../utils/scale';
8
+ import { DefaultScrubberBeacon } from './DefaultScrubberBeacon';
9
+ import { jsx as _jsx } from "react/jsx-runtime";
10
+ // Helper component to calculate beacon data for a specific series
11
+ const BeaconWithData = /*#__PURE__*/memo(_ref => {
12
+ let {
13
+ seriesId,
14
+ dataIndex,
15
+ dataX,
16
+ isIdle,
17
+ BeaconComponent,
18
+ idlePulse,
19
+ animate,
20
+ transitions,
21
+ beaconRef,
22
+ stroke
23
+ } = _ref;
24
+ const {
25
+ getSeries,
26
+ getSeriesData,
27
+ getXScale,
28
+ getYScale
29
+ } = useCartesianChartContext();
30
+ const theme = useTheme();
31
+ const series = useMemo(() => getSeries(seriesId), [getSeries, seriesId]);
32
+ const sourceData = useMemo(() => getSeriesData(seriesId), [getSeriesData, seriesId]);
33
+ const gradient = series == null ? void 0 : series.gradient;
34
+ const dataY = useDerivedValue(() => {
35
+ if (sourceData && dataIndex.value !== undefined && dataIndex.value >= 0 && dataIndex.value < sourceData.length) {
36
+ const dataValue = sourceData[dataIndex.value];
37
+ if (typeof dataValue === 'number') {
38
+ return dataValue;
39
+ } else if (Array.isArray(dataValue)) {
40
+ const validValues = dataValue.filter(val => val !== null);
41
+ if (validValues.length >= 1) {
42
+ return validValues[validValues.length - 1];
43
+ }
44
+ }
45
+ }
46
+ return 0;
47
+ }, [sourceData, dataIndex]);
48
+
49
+ // Get scales for gradient evaluation
50
+ const gradientScale = useMemo(() => {
51
+ if (!gradient) return undefined;
52
+ const scale = gradient.axis === 'x' ? getXScale() : getYScale(series == null ? void 0 : series.yAxisId);
53
+ if (!scale) return undefined;
54
+ return convertToSerializableScale(scale);
55
+ }, [gradient, getXScale, getYScale, series == null ? void 0 : series.yAxisId]);
56
+ const gradientStops = useMemo(() => {
57
+ if (!gradient || !gradientScale) return undefined;
58
+ const domain = {
59
+ min: gradientScale.domain[0],
60
+ max: gradientScale.domain[1]
61
+ };
62
+ return getGradientStops(gradient.stops, domain);
63
+ }, [gradient, gradientScale]);
64
+
65
+ // Evaluate gradient color on UI thread
66
+ const color = useDerivedValue(() => {
67
+ 'worklet';
68
+
69
+ // Evaluate gradient if present
70
+ var _series$color;
71
+ if (gradient && gradientScale && gradientStops) {
72
+ var _gradient$axis;
73
+ const axis = (_gradient$axis = gradient.axis) != null ? _gradient$axis : 'y';
74
+ const dataValue = axis === 'x' ? dataX.value : dataY.value;
75
+ if (dataValue !== undefined) {
76
+ const evaluatedColor = evaluateGradientAtValue(gradientStops, dataValue, gradientScale);
77
+ if (evaluatedColor) {
78
+ return evaluatedColor;
79
+ }
80
+ }
81
+ }
82
+
83
+ // Fallback to series color
84
+ return (_series$color = series == null ? void 0 : series.color) != null ? _series$color : theme.color.fgPrimary;
85
+ }, [gradient, gradientScale, gradientStops, dataX, dataY, series == null ? void 0 : series.color, theme.color.fgPrimary]);
86
+ return /*#__PURE__*/_jsx(BeaconComponent, {
87
+ ref: beaconRef,
88
+ animate: animate,
89
+ color: color,
90
+ dataX: dataX,
91
+ dataY: dataY,
92
+ idlePulse: idlePulse,
93
+ isIdle: isIdle,
94
+ seriesId: seriesId,
95
+ stroke: stroke,
96
+ transitions: transitions
97
+ });
98
+ });
99
+ export const ScrubberBeaconGroup = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref2, ref) => {
100
+ let {
101
+ seriesIds,
102
+ idlePulse,
103
+ transitions,
104
+ BeaconComponent = DefaultScrubberBeacon,
105
+ stroke
106
+ } = _ref2;
107
+ const ScrubberBeaconRefs = useRefMap();
108
+ const {
109
+ scrubberPosition
110
+ } = useScrubberContext();
111
+ const {
112
+ getXAxis,
113
+ series,
114
+ dataLength,
115
+ animate
116
+ } = useCartesianChartContext();
117
+ const xAxis = useMemo(() => getXAxis(), [getXAxis]);
118
+
119
+ // Expose imperative handle with pulse method
120
+ useImperativeHandle(ref, () => ({
121
+ pulse: () => {
122
+ Object.values(ScrubberBeaconRefs.refs).forEach(beaconRef => {
123
+ beaconRef == null || beaconRef.pulse();
124
+ });
125
+ }
126
+ }));
127
+ const filteredSeries = useMemo(() => {
128
+ var _series$filter;
129
+ return (_series$filter = series == null ? void 0 : series.filter(s => seriesIds.includes(s.id))) != null ? _series$filter : [];
130
+ }, [series, seriesIds]);
131
+ const dataIndex = useDerivedValue(() => {
132
+ var _scrubberPosition$val;
133
+ return (_scrubberPosition$val = scrubberPosition.value) != null ? _scrubberPosition$val : Math.max(0, dataLength - 1);
134
+ }, [scrubberPosition, dataLength]);
135
+ const dataX = useDerivedValue(() => {
136
+ // Convert index to actual x value if axis has data
137
+ if (xAxis != null && xAxis.data && Array.isArray(xAxis.data) && xAxis.data[dataIndex.value] !== undefined) {
138
+ const dataValue = xAxis.data[dataIndex.value];
139
+ return typeof dataValue === 'string' ? dataIndex.value : dataValue;
140
+ }
141
+ return dataIndex.value;
142
+ }, [xAxis, dataIndex]);
143
+ const isIdle = useDerivedValue(() => {
144
+ return scrubberPosition.value === undefined;
145
+ }, [scrubberPosition]);
146
+ const createBeaconRef = useCallback(seriesId => {
147
+ return beaconRef => {
148
+ if (beaconRef) {
149
+ ScrubberBeaconRefs.registerRef(seriesId, beaconRef);
150
+ }
151
+ };
152
+ }, [ScrubberBeaconRefs]);
153
+ return filteredSeries.map(s => /*#__PURE__*/_jsx(BeaconWithData, {
154
+ BeaconComponent: BeaconComponent,
155
+ animate: animate,
156
+ beaconRef: createBeaconRef(s.id),
157
+ dataIndex: dataIndex,
158
+ dataX: dataX,
159
+ idlePulse: idlePulse,
160
+ isIdle: isIdle,
161
+ seriesId: s.id,
162
+ stroke: stroke,
163
+ transitions: transitions
164
+ }, s.id));
165
+ }));