@coinbase/cds-mobile-visualization 3.3.0 → 3.4.0-beta.10

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 (265) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/dts/chart/CartesianChart.d.ts +125 -0
  3. package/dts/chart/CartesianChart.d.ts.map +1 -0
  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 +6 -0
  7. package/dts/chart/ChartProvider.d.ts.map +1 -0
  8. package/dts/chart/Path.d.ts +91 -0
  9. package/dts/chart/Path.d.ts.map +1 -0
  10. package/dts/chart/PeriodSelector.d.ts +85 -0
  11. package/dts/chart/PeriodSelector.d.ts.map +1 -0
  12. package/dts/chart/area/Area.d.ts +77 -0
  13. package/dts/chart/area/Area.d.ts.map +1 -0
  14. package/dts/chart/area/AreaChart.d.ts +131 -0
  15. package/dts/chart/area/AreaChart.d.ts.map +1 -0
  16. package/dts/chart/area/DottedArea.d.ts +46 -0
  17. package/dts/chart/area/DottedArea.d.ts.map +1 -0
  18. package/dts/chart/area/GradientArea.d.ts +36 -0
  19. package/dts/chart/area/GradientArea.d.ts.map +1 -0
  20. package/dts/chart/area/SolidArea.d.ts +23 -0
  21. package/dts/chart/area/SolidArea.d.ts.map +1 -0
  22. package/dts/chart/area/index.d.ts +6 -0
  23. package/dts/chart/area/index.d.ts.map +1 -0
  24. package/dts/chart/axis/Axis.d.ts +194 -0
  25. package/dts/chart/axis/Axis.d.ts.map +1 -0
  26. package/dts/chart/axis/DefaultAxisTickLabel.d.ts +8 -0
  27. package/dts/chart/axis/DefaultAxisTickLabel.d.ts.map +1 -0
  28. package/dts/chart/axis/XAxis.d.ts +16 -0
  29. package/dts/chart/axis/XAxis.d.ts.map +1 -0
  30. package/dts/chart/axis/YAxis.d.ts +21 -0
  31. package/dts/chart/axis/YAxis.d.ts.map +1 -0
  32. package/dts/chart/axis/index.d.ts +5 -0
  33. package/dts/chart/axis/index.d.ts.map +1 -0
  34. package/dts/chart/bar/Bar.d.ts +92 -0
  35. package/dts/chart/bar/Bar.d.ts.map +1 -0
  36. package/dts/chart/bar/BarChart.d.ts +113 -0
  37. package/dts/chart/bar/BarChart.d.ts.map +1 -0
  38. package/dts/chart/bar/BarPlot.d.ts +30 -0
  39. package/dts/chart/bar/BarPlot.d.ts.map +1 -0
  40. package/dts/chart/bar/BarStack.d.ts +102 -0
  41. package/dts/chart/bar/BarStack.d.ts.map +1 -0
  42. package/dts/chart/bar/BarStackGroup.d.ts +36 -0
  43. package/dts/chart/bar/BarStackGroup.d.ts.map +1 -0
  44. package/dts/chart/bar/DefaultBar.d.ts +7 -0
  45. package/dts/chart/bar/DefaultBar.d.ts.map +1 -0
  46. package/dts/chart/bar/DefaultBarStack.d.ts +7 -0
  47. package/dts/chart/bar/DefaultBarStack.d.ts.map +1 -0
  48. package/dts/chart/bar/index.d.ts +8 -0
  49. package/dts/chart/bar/index.d.ts.map +1 -0
  50. package/dts/chart/gradient/Gradient.d.ts +25 -0
  51. package/dts/chart/gradient/Gradient.d.ts.map +1 -0
  52. package/dts/chart/gradient/index.d.ts +2 -0
  53. package/dts/chart/gradient/index.d.ts.map +1 -0
  54. package/dts/chart/index.d.ts +15 -0
  55. package/dts/chart/index.d.ts.map +1 -0
  56. package/dts/chart/line/DefaultReferenceLineLabel.d.ts +9 -0
  57. package/dts/chart/line/DefaultReferenceLineLabel.d.ts.map +1 -0
  58. package/dts/chart/line/DottedLine.d.ts +20 -0
  59. package/dts/chart/line/DottedLine.d.ts.map +1 -0
  60. package/dts/chart/line/Line.d.ts +115 -0
  61. package/dts/chart/line/Line.d.ts.map +1 -0
  62. package/dts/chart/line/LineChart.d.ts +118 -0
  63. package/dts/chart/line/LineChart.d.ts.map +1 -0
  64. package/dts/chart/line/ReferenceLine.d.ts +139 -0
  65. package/dts/chart/line/ReferenceLine.d.ts.map +1 -0
  66. package/dts/chart/line/SolidLine.d.ts +15 -0
  67. package/dts/chart/line/SolidLine.d.ts.map +1 -0
  68. package/dts/chart/line/index.d.ts +7 -0
  69. package/dts/chart/line/index.d.ts.map +1 -0
  70. package/dts/chart/point/DefaultPointLabel.d.ts +10 -0
  71. package/dts/chart/point/DefaultPointLabel.d.ts.map +1 -0
  72. package/dts/chart/point/Point.d.ts +120 -0
  73. package/dts/chart/point/Point.d.ts.map +1 -0
  74. package/dts/chart/point/index.d.ts +3 -0
  75. package/dts/chart/point/index.d.ts.map +1 -0
  76. package/dts/chart/scrubber/DefaultScrubberBeacon.d.ts +8 -0
  77. package/dts/chart/scrubber/DefaultScrubberBeacon.d.ts.map +1 -0
  78. package/dts/chart/scrubber/DefaultScrubberBeaconLabel.d.ts +12 -0
  79. package/dts/chart/scrubber/DefaultScrubberBeaconLabel.d.ts.map +1 -0
  80. package/dts/chart/scrubber/DefaultScrubberLabel.d.ts +11 -0
  81. package/dts/chart/scrubber/DefaultScrubberLabel.d.ts.map +1 -0
  82. package/dts/chart/scrubber/Scrubber.d.ts +233 -0
  83. package/dts/chart/scrubber/Scrubber.d.ts.map +1 -0
  84. package/dts/chart/scrubber/ScrubberBeaconGroup.d.ts +44 -0
  85. package/dts/chart/scrubber/ScrubberBeaconGroup.d.ts.map +1 -0
  86. package/dts/chart/scrubber/ScrubberBeaconLabelGroup.d.ts +31 -0
  87. package/dts/chart/scrubber/ScrubberBeaconLabelGroup.d.ts.map +1 -0
  88. package/dts/chart/scrubber/ScrubberProvider.d.ts +20 -0
  89. package/dts/chart/scrubber/ScrubberProvider.d.ts.map +1 -0
  90. package/dts/chart/scrubber/index.d.ts +5 -0
  91. package/dts/chart/scrubber/index.d.ts.map +1 -0
  92. package/dts/chart/text/ChartText.d.ts +164 -0
  93. package/dts/chart/text/ChartText.d.ts.map +1 -0
  94. package/dts/chart/text/ChartTextGroup.d.ts +61 -0
  95. package/dts/chart/text/ChartTextGroup.d.ts.map +1 -0
  96. package/dts/chart/text/index.d.ts +3 -0
  97. package/dts/chart/text/index.d.ts.map +1 -0
  98. package/dts/chart/utils/axis.d.ts +342 -0
  99. package/dts/chart/utils/axis.d.ts.map +1 -0
  100. package/dts/chart/utils/bar.d.ts +20 -0
  101. package/dts/chart/utils/bar.d.ts.map +1 -0
  102. package/dts/chart/utils/chart.d.ts +124 -0
  103. package/dts/chart/utils/chart.d.ts.map +1 -0
  104. package/dts/chart/utils/context.d.ts +116 -0
  105. package/dts/chart/utils/context.d.ts.map +1 -0
  106. package/dts/chart/utils/gradient.d.ts +117 -0
  107. package/dts/chart/utils/gradient.d.ts.map +1 -0
  108. package/dts/chart/utils/index.d.ts +11 -0
  109. package/dts/chart/utils/index.d.ts.map +1 -0
  110. package/dts/chart/utils/path.d.ts +160 -0
  111. package/dts/chart/utils/path.d.ts.map +1 -0
  112. package/dts/chart/utils/point.d.ts +134 -0
  113. package/dts/chart/utils/point.d.ts.map +1 -0
  114. package/dts/chart/utils/scale.d.ts +134 -0
  115. package/dts/chart/utils/scale.d.ts.map +1 -0
  116. package/dts/chart/utils/scrubber.d.ts +39 -0
  117. package/dts/chart/utils/scrubber.d.ts.map +1 -0
  118. package/dts/chart/utils/transition.d.ts +140 -0
  119. package/dts/chart/utils/transition.d.ts.map +1 -0
  120. package/dts/index.d.ts +2 -1
  121. package/dts/index.d.ts.map +1 -1
  122. package/dts/sparkline/Counter.d.ts +7 -2
  123. package/dts/sparkline/Sparkline.d.ts +67 -16
  124. package/dts/sparkline/Sparkline.d.ts.map +1 -1
  125. package/dts/sparkline/SparklineArea.d.ts +10 -4
  126. package/dts/sparkline/SparklineArea.d.ts.map +1 -1
  127. package/dts/sparkline/SparklineAreaPattern.d.ts +12 -4
  128. package/dts/sparkline/SparklineAreaPattern.d.ts.map +1 -1
  129. package/dts/sparkline/SparklineGradient.d.ts +21 -10
  130. package/dts/sparkline/SparklineGradient.d.ts.map +1 -1
  131. package/dts/sparkline/__figma__/Sparkline.figma.d.ts +1 -1
  132. package/dts/sparkline/generateSparklineWithId.d.ts +8 -2
  133. package/dts/sparkline/generateSparklineWithId.d.ts.map +1 -1
  134. package/dts/sparkline/index.d.ts +1 -1
  135. package/dts/sparkline/sparkline-interactive/SparklineAccessibleView.d.ts +8 -3
  136. package/dts/sparkline/sparkline-interactive/SparklineInteractive.d.ts +132 -110
  137. package/dts/sparkline/sparkline-interactive/SparklineInteractive.d.ts.map +1 -1
  138. package/dts/sparkline/sparkline-interactive/SparklineInteractiveAnimatedPath.d.ts +22 -9
  139. package/dts/sparkline/sparkline-interactive/SparklineInteractiveAnimatedPath.d.ts.map +1 -1
  140. package/dts/sparkline/sparkline-interactive/SparklineInteractiveHoverDate.d.ts +18 -7
  141. package/dts/sparkline/sparkline-interactive/SparklineInteractiveLineVertical.d.ts +9 -4
  142. package/dts/sparkline/sparkline-interactive/SparklineInteractiveMarkerDates.d.ts +11 -6
  143. package/dts/sparkline/sparkline-interactive/SparklineInteractiveMinMax.d.ts +7 -5
  144. package/dts/sparkline/sparkline-interactive/SparklineInteractivePanGestureHandler.d.ts +22 -10
  145. package/dts/sparkline/sparkline-interactive/SparklineInteractivePaths.d.ts +21 -7
  146. package/dts/sparkline/sparkline-interactive/SparklineInteractivePaths.d.ts.map +1 -1
  147. package/dts/sparkline/sparkline-interactive/SparklineInteractivePeriodSelector.d.ts +21 -16
  148. package/dts/sparkline/sparkline-interactive/SparklineInteractiveProvider.d.ts +29 -23
  149. package/dts/sparkline/sparkline-interactive/SparklineInteractiveTimeseriesPaths.d.ts +22 -14
  150. package/dts/sparkline/sparkline-interactive/__figma__/SparklineInteractive.figma.d.ts +1 -1
  151. package/dts/sparkline/sparkline-interactive/useInterruptiblePathAnimation.d.ts +9 -5
  152. package/dts/sparkline/sparkline-interactive/useMinMaxTransform.d.ts +11 -6
  153. package/dts/sparkline/sparkline-interactive/useOpacityAnimation.d.ts +5 -2
  154. package/dts/sparkline/sparkline-interactive/useSparklineInteractiveConstants.d.ts +17 -17
  155. package/dts/sparkline/sparkline-interactive/useSparklineInteractiveLineStyles.d.ts +16 -13
  156. package/dts/sparkline/sparkline-interactive-header/SparklineInteractiveHeader.d.ts +106 -98
  157. package/dts/sparkline/sparkline-interactive-header/__figma__/SparklineInteractiveHeader.figma.d.ts +1 -1
  158. package/dts/sparkline/sparkline-interactive-header/useSparklineInteractiveHeaderStyles.d.ts +22 -19
  159. package/esm/chart/CartesianChart.js +335 -0
  160. package/esm/chart/ChartContextBridge.js +148 -0
  161. package/esm/chart/ChartProvider.js +10 -0
  162. package/esm/chart/Path.js +218 -0
  163. package/esm/chart/PeriodSelector.js +136 -0
  164. package/esm/chart/__stories__/CartesianChart.stories.js +723 -0
  165. package/esm/chart/__stories__/Chart.stories.js +77 -0
  166. package/esm/chart/__stories__/PeriodSelector.stories.js +322 -0
  167. package/esm/chart/area/Area.js +75 -0
  168. package/esm/chart/area/AreaChart.js +151 -0
  169. package/esm/chart/area/DottedArea.js +80 -0
  170. package/esm/chart/area/GradientArea.js +54 -0
  171. package/esm/chart/area/SolidArea.js +38 -0
  172. package/esm/chart/area/__stories__/AreaChart.stories.js +100 -0
  173. package/esm/chart/area/index.js +7 -0
  174. package/esm/chart/axis/Axis.js +45 -0
  175. package/esm/chart/axis/DefaultAxisTickLabel.js +11 -0
  176. package/esm/chart/axis/XAxis.js +188 -0
  177. package/esm/chart/axis/YAxis.js +177 -0
  178. package/esm/chart/axis/__stories__/Axis.stories.js +276 -0
  179. package/esm/chart/axis/index.js +6 -0
  180. package/esm/chart/bar/Bar.js +69 -0
  181. package/esm/chart/bar/BarChart.js +125 -0
  182. package/esm/chart/bar/BarPlot.js +102 -0
  183. package/esm/chart/bar/BarStack.js +551 -0
  184. package/esm/chart/bar/BarStackGroup.js +79 -0
  185. package/esm/chart/bar/DefaultBar.js +56 -0
  186. package/esm/chart/bar/DefaultBarStack.js +47 -0
  187. package/esm/chart/bar/__stories__/BarChart.stories.js +668 -0
  188. package/esm/chart/bar/index.js +9 -0
  189. package/esm/chart/gradient/Gradient.js +53 -0
  190. package/esm/chart/gradient/index.js +1 -0
  191. package/esm/chart/index.js +16 -0
  192. package/esm/chart/line/DefaultReferenceLineLabel.js +66 -0
  193. package/esm/chart/line/DottedLine.js +50 -0
  194. package/esm/chart/line/Line.js +178 -0
  195. package/esm/chart/line/LineChart.js +121 -0
  196. package/esm/chart/line/ReferenceLine.js +132 -0
  197. package/esm/chart/line/SolidLine.js +46 -0
  198. package/esm/chart/line/__stories__/LineChart.stories.js +2372 -0
  199. package/esm/chart/line/__stories__/ReferenceLine.stories.js +132 -0
  200. package/esm/chart/line/index.js +8 -0
  201. package/esm/chart/point/DefaultPointLabel.js +39 -0
  202. package/esm/chart/point/Point.js +188 -0
  203. package/esm/chart/point/index.js +2 -0
  204. package/esm/chart/scrubber/DefaultScrubberBeacon.js +179 -0
  205. package/esm/chart/scrubber/DefaultScrubberBeaconLabel.js +43 -0
  206. package/esm/chart/scrubber/DefaultScrubberLabel.js +28 -0
  207. package/esm/chart/scrubber/Scrubber.js +166 -0
  208. package/esm/chart/scrubber/ScrubberBeaconGroup.js +161 -0
  209. package/esm/chart/scrubber/ScrubberBeaconLabelGroup.js +185 -0
  210. package/esm/chart/scrubber/ScrubberProvider.js +135 -0
  211. package/esm/chart/scrubber/index.js +4 -0
  212. package/esm/chart/text/ChartText.js +305 -0
  213. package/esm/chart/text/ChartTextGroup.js +211 -0
  214. package/esm/chart/text/index.js +4 -0
  215. package/esm/chart/utils/axis.js +592 -0
  216. package/esm/chart/utils/bar.js +24 -0
  217. package/esm/chart/utils/chart.js +270 -0
  218. package/esm/chart/utils/context.js +15 -0
  219. package/esm/chart/utils/gradient.js +305 -0
  220. package/esm/chart/utils/index.js +12 -0
  221. package/esm/chart/utils/path.js +274 -0
  222. package/esm/chart/utils/point.js +229 -0
  223. package/esm/chart/utils/scale.js +277 -0
  224. package/esm/chart/utils/scrubber.js +139 -0
  225. package/esm/chart/utils/transition.js +185 -0
  226. package/esm/index.js +4 -1
  227. package/esm/sparkline/Sparkline.js +129 -16
  228. package/esm/sparkline/SparklineArea.js +7 -2
  229. package/esm/sparkline/SparklineAreaPattern.js +4 -2
  230. package/esm/sparkline/SparklineGradient.js +4 -0
  231. package/esm/sparkline/__stories__/Sparkline.stories.js +11 -7
  232. package/esm/sparkline/__stories__/SparklineGradient.stories.js +7 -4
  233. package/esm/sparkline/generateSparklineWithId.js +3 -2
  234. package/esm/sparkline/sparkline-interactive/SparklineInteractive.js +5 -1
  235. package/esm/sparkline/sparkline-interactive/SparklineInteractiveAnimatedPath.js +5 -2
  236. package/esm/sparkline/sparkline-interactive/SparklineInteractivePaths.js +4 -0
  237. package/esm/sparkline/sparkline-interactive/__stories__/SparklineInteractive.stories.js +76 -24
  238. package/esm/sparkline/sparkline-interactive-header/__stories__/SparklineInteractiveHeader.stories.js +17 -9
  239. package/package.json +17 -11
  240. package/dts/sparkline/__stories__/Sparkline.stories.d.ts +0 -3
  241. package/dts/sparkline/__stories__/Sparkline.stories.d.ts.map +0 -1
  242. package/dts/sparkline/__stories__/SparklineGradient.stories.d.ts +0 -3
  243. package/dts/sparkline/__stories__/SparklineGradient.stories.d.ts.map +0 -1
  244. package/dts/sparkline/sparkline-interactive/__stories__/SparklineInteractive.stories.d.ts +0 -3
  245. package/dts/sparkline/sparkline-interactive/__stories__/SparklineInteractive.stories.d.ts.map +0 -1
  246. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractive.test.d.ts +0 -2
  247. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractive.test.d.ts.map +0 -1
  248. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractiveHoverDate.test.d.ts +0 -2
  249. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractiveHoverDate.test.d.ts.map +0 -1
  250. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractivePanGestureHandler.test.d.ts +0 -2
  251. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractivePanGestureHandler.test.d.ts.map +0 -1
  252. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractivePeriodSelector.test.d.ts +0 -2
  253. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractivePeriodSelector.test.d.ts.map +0 -1
  254. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractiveTimeseriesPaths.test.d.ts +0 -2
  255. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractiveTimeseriesPaths.test.d.ts.map +0 -1
  256. package/dts/sparkline/sparkline-interactive/__tests__/useMinMaxTransform.test.d.ts +0 -2
  257. package/dts/sparkline/sparkline-interactive/__tests__/useMinMaxTransform.test.d.ts.map +0 -1
  258. package/dts/sparkline/sparkline-interactive/useInterruptiblePathAnimation.test.disable.d.ts +0 -2
  259. package/dts/sparkline/sparkline-interactive/useInterruptiblePathAnimation.test.disable.d.ts.map +0 -1
  260. package/dts/sparkline/sparkline-interactive-header/__stories__/SparklineInteractiveHeader.stories.d.ts +0 -4
  261. package/dts/sparkline/sparkline-interactive-header/__stories__/SparklineInteractiveHeader.stories.d.ts.map +0 -1
  262. package/dts/sparkline/sparkline-interactive-header/__tests__/SparklineInteractiveHeader.test.d.ts +0 -2
  263. package/dts/sparkline/sparkline-interactive-header/__tests__/SparklineInteractiveHeader.test.d.ts.map +0 -1
  264. package/dts/sparkline/sparkline-interactive-header/__tests__/useSparklineInteractiveHeaderStyles.test.d.ts +0 -2
  265. package/dts/sparkline/sparkline-interactive-header/__tests__/useSparklineInteractiveHeaderStyles.test.d.ts.map +0 -1
@@ -0,0 +1,166 @@
1
+ import React, { forwardRef, memo, useCallback, useEffect, useImperativeHandle, useMemo } from 'react';
2
+ import { runOnJS, useAnimatedReaction, useDerivedValue, useSharedValue, withDelay, withTiming } from 'react-native-reanimated';
3
+ import { useTheme } from '@coinbase/cds-mobile';
4
+ import { Group, Rect } from '@shopify/react-native-skia';
5
+ import { useCartesianChartContext } from '../ChartProvider';
6
+ import { ReferenceLine } from '../line';
7
+ import { accessoryFadeTransitionDelay, accessoryFadeTransitionDuration, getPointOnSerializableScale, useScrubberContext } from '../utils';
8
+ import { DefaultScrubberBeacon } from './DefaultScrubberBeacon';
9
+ import { DefaultScrubberLabel } from './DefaultScrubberLabel';
10
+ import { ScrubberBeaconGroup } from './ScrubberBeaconGroup';
11
+ import { ScrubberBeaconLabelGroup } from './ScrubberBeaconLabelGroup';
12
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
+ /**
14
+ * Unified component that manages all scrubber elements (beacons, line, labels).
15
+ */
16
+ export const Scrubber = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) => {
17
+ let {
18
+ seriesIds,
19
+ hideLine,
20
+ label,
21
+ lineStroke,
22
+ BeaconComponent = DefaultScrubberBeacon,
23
+ BeaconLabelComponent,
24
+ LineComponent,
25
+ LabelComponent = DefaultScrubberLabel,
26
+ labelElevated,
27
+ hideOverlay,
28
+ overlayOffset = 2,
29
+ beaconLabelMinGap,
30
+ beaconLabelHorizontalOffset,
31
+ labelFont,
32
+ labelBoundsInset,
33
+ beaconLabelFont,
34
+ idlePulse,
35
+ beaconTransitions
36
+ } = _ref;
37
+ const theme = useTheme();
38
+ const beaconGroupRef = React.useRef(null);
39
+ const {
40
+ scrubberPosition
41
+ } = useScrubberContext();
42
+ const {
43
+ getXSerializableScale,
44
+ getXAxis,
45
+ series,
46
+ drawingArea,
47
+ animate,
48
+ dataLength
49
+ } = useCartesianChartContext();
50
+ const xAxis = useMemo(() => getXAxis(), [getXAxis]);
51
+ const xScale = useMemo(() => getXSerializableScale(), [getXSerializableScale]);
52
+
53
+ // Animation state for delayed scrubber rendering (matches web timing)
54
+ const scrubberOpacity = useSharedValue(animate ? 0 : 1);
55
+
56
+ // Delay scrubber appearance until after path enter animation completes
57
+ useEffect(() => {
58
+ if (animate) {
59
+ scrubberOpacity.value = withDelay(accessoryFadeTransitionDelay, withTiming(1, {
60
+ duration: accessoryFadeTransitionDuration
61
+ }));
62
+ }
63
+ }, [animate, scrubberOpacity]);
64
+
65
+ // Expose imperative handle with pulse method
66
+ useImperativeHandle(ref, () => ({
67
+ pulse: () => {
68
+ var _beaconGroupRef$curre;
69
+ (_beaconGroupRef$curre = beaconGroupRef.current) == null || _beaconGroupRef$curre.pulse();
70
+ }
71
+ }));
72
+ const filteredSeriesIds = useMemo(() => {
73
+ if (seriesIds === undefined) {
74
+ var _series$map;
75
+ return (_series$map = series == null ? void 0 : series.map(s => s.id)) != null ? _series$map : [];
76
+ }
77
+ return seriesIds;
78
+ }, [series, seriesIds]);
79
+ const dataIndex = useDerivedValue(() => {
80
+ var _scrubberPosition$val;
81
+ return (_scrubberPosition$val = scrubberPosition.value) != null ? _scrubberPosition$val : Math.max(0, dataLength - 1);
82
+ }, [scrubberPosition, dataLength]);
83
+ const dataX = useDerivedValue(() => {
84
+ if (xAxis != null && xAxis.data && Array.isArray(xAxis.data) && xAxis.data[dataIndex.value] !== undefined) {
85
+ const dataValue = xAxis.data[dataIndex.value];
86
+ return typeof dataValue === 'string' ? dataIndex.value : dataValue;
87
+ }
88
+ return dataIndex.value;
89
+ }, [xAxis, dataIndex]);
90
+ const lineOpacity = useDerivedValue(() => {
91
+ return scrubberPosition.value !== undefined ? 1 : 0;
92
+ }, [scrubberPosition]);
93
+ const overlayOpacity = useDerivedValue(() => {
94
+ return scrubberPosition.value !== undefined ? 0.8 : 0;
95
+ }, [scrubberPosition]);
96
+ const overlayWidth = useDerivedValue(() => {
97
+ const pixelX = dataX.value !== undefined && xScale ? getPointOnSerializableScale(dataX.value, xScale) : 0;
98
+ return drawingArea.x + drawingArea.width - pixelX + overlayOffset;
99
+ }, [dataX, xScale]);
100
+ const overlayX = useDerivedValue(() => {
101
+ const xValue = dataX.value !== undefined && xScale ? getPointOnSerializableScale(dataX.value, xScale) : 0;
102
+ return xValue;
103
+ }, [dataX, xScale]);
104
+ const resolvedLabelValue = useSharedValue('');
105
+ const updateResolvedLabel = useCallback(index => {
106
+ if (!label) {
107
+ resolvedLabelValue.value = '';
108
+ return;
109
+ }
110
+ if (typeof label === 'function') {
111
+ const result = label(index);
112
+ resolvedLabelValue.value = result != null ? result : '';
113
+ } else if (typeof label === 'string') {
114
+ resolvedLabelValue.value = label;
115
+ }
116
+ }, [label, resolvedLabelValue]);
117
+
118
+ // Update resolved label when dataIndex changes
119
+ useAnimatedReaction(() => dataIndex.value, currentIndex => {
120
+ 'worklet';
121
+
122
+ runOnJS(updateResolvedLabel)(currentIndex);
123
+ }, [updateResolvedLabel]);
124
+ const beaconLabels = useMemo(() => {
125
+ var _series$filter$filter;
126
+ 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 => ({
127
+ seriesId: s.id,
128
+ label: s.label,
129
+ color: s.color
130
+ }))) != null ? _series$filter$filter : [];
131
+ }, [series, filteredSeriesIds]);
132
+ if (!xScale) return;
133
+ return /*#__PURE__*/_jsxs(Group, {
134
+ opacity: scrubberOpacity,
135
+ children: [!hideOverlay && /*#__PURE__*/_jsx(Rect, {
136
+ color: theme.color.bg,
137
+ height: drawingArea.height + overlayOffset * 2,
138
+ opacity: overlayOpacity,
139
+ width: overlayWidth,
140
+ x: overlayX,
141
+ y: drawingArea.y - overlayOffset
142
+ }), !hideLine && /*#__PURE__*/_jsx(ReferenceLine, {
143
+ LabelComponent: LabelComponent,
144
+ LineComponent: LineComponent,
145
+ dataX: dataX,
146
+ label: resolvedLabelValue,
147
+ labelBoundsInset: labelBoundsInset,
148
+ labelElevated: labelElevated,
149
+ labelFont: labelFont,
150
+ opacity: lineOpacity,
151
+ stroke: lineStroke
152
+ }), /*#__PURE__*/_jsx(ScrubberBeaconGroup, {
153
+ ref: beaconGroupRef,
154
+ BeaconComponent: BeaconComponent,
155
+ idlePulse: idlePulse,
156
+ seriesIds: filteredSeriesIds,
157
+ transitions: beaconTransitions
158
+ }), beaconLabels.length > 0 && /*#__PURE__*/_jsx(ScrubberBeaconLabelGroup, {
159
+ BeaconLabelComponent: BeaconLabelComponent,
160
+ labelFont: beaconLabelFont,
161
+ labelHorizontalOffset: beaconLabelHorizontalOffset,
162
+ labelMinGap: beaconLabelMinGap,
163
+ labels: beaconLabels
164
+ })]
165
+ });
166
+ }));
@@ -0,0 +1,161 @@
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
+ } = _ref;
23
+ const {
24
+ getSeries,
25
+ getSeriesData,
26
+ getXScale,
27
+ getYScale
28
+ } = useCartesianChartContext();
29
+ const theme = useTheme();
30
+ const series = useMemo(() => getSeries(seriesId), [getSeries, seriesId]);
31
+ const sourceData = useMemo(() => getSeriesData(seriesId), [getSeriesData, seriesId]);
32
+ const gradient = series == null ? void 0 : series.gradient;
33
+ const dataY = useDerivedValue(() => {
34
+ if (sourceData && dataIndex.value !== undefined && dataIndex.value >= 0 && dataIndex.value < sourceData.length) {
35
+ const dataValue = sourceData[dataIndex.value];
36
+ if (typeof dataValue === 'number') {
37
+ return dataValue;
38
+ } else if (Array.isArray(dataValue)) {
39
+ const validValues = dataValue.filter(val => val !== null);
40
+ if (validValues.length >= 1) {
41
+ return validValues[validValues.length - 1];
42
+ }
43
+ }
44
+ }
45
+ return 0;
46
+ }, [sourceData, dataIndex]);
47
+
48
+ // Get scales for gradient evaluation
49
+ const gradientScale = useMemo(() => {
50
+ if (!gradient) return undefined;
51
+ const scale = gradient.axis === 'x' ? getXScale() : getYScale(series == null ? void 0 : series.yAxisId);
52
+ if (!scale) return undefined;
53
+ return convertToSerializableScale(scale);
54
+ }, [gradient, getXScale, getYScale, series == null ? void 0 : series.yAxisId]);
55
+ const gradientStops = useMemo(() => {
56
+ if (!gradient || !gradientScale) return undefined;
57
+ const domain = {
58
+ min: gradientScale.domain[0],
59
+ max: gradientScale.domain[1]
60
+ };
61
+ return getGradientStops(gradient.stops, domain);
62
+ }, [gradient, gradientScale]);
63
+
64
+ // Evaluate gradient color on UI thread
65
+ const color = useDerivedValue(() => {
66
+ 'worklet';
67
+
68
+ // Evaluate gradient if present
69
+ var _series$color;
70
+ if (gradient && gradientScale && gradientStops) {
71
+ var _gradient$axis;
72
+ const axis = (_gradient$axis = gradient.axis) != null ? _gradient$axis : 'y';
73
+ const dataValue = axis === 'x' ? dataX.value : dataY.value;
74
+ if (dataValue !== undefined) {
75
+ const evaluatedColor = evaluateGradientAtValue(gradientStops, dataValue, gradientScale);
76
+ if (evaluatedColor) {
77
+ return evaluatedColor;
78
+ }
79
+ }
80
+ }
81
+
82
+ // Fallback to series color
83
+ return (_series$color = series == null ? void 0 : series.color) != null ? _series$color : theme.color.fgPrimary;
84
+ }, [gradient, gradientScale, gradientStops, dataX, dataY, series == null ? void 0 : series.color, theme.color.fgPrimary]);
85
+ return /*#__PURE__*/_jsx(BeaconComponent, {
86
+ ref: beaconRef,
87
+ animate: animate,
88
+ color: color,
89
+ dataX: dataX,
90
+ dataY: dataY,
91
+ idlePulse: idlePulse,
92
+ isIdle: isIdle,
93
+ seriesId: seriesId,
94
+ transitions: transitions
95
+ });
96
+ });
97
+ export const ScrubberBeaconGroup = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref2, ref) => {
98
+ let {
99
+ seriesIds,
100
+ idlePulse,
101
+ transitions,
102
+ BeaconComponent = DefaultScrubberBeacon
103
+ } = _ref2;
104
+ const ScrubberBeaconRefs = useRefMap();
105
+ const {
106
+ scrubberPosition
107
+ } = useScrubberContext();
108
+ const {
109
+ getXAxis,
110
+ series,
111
+ dataLength,
112
+ animate
113
+ } = useCartesianChartContext();
114
+ const xAxis = useMemo(() => getXAxis(), [getXAxis]);
115
+
116
+ // Expose imperative handle with pulse method
117
+ useImperativeHandle(ref, () => ({
118
+ pulse: () => {
119
+ Object.values(ScrubberBeaconRefs.refs).forEach(beaconRef => {
120
+ beaconRef == null || beaconRef.pulse();
121
+ });
122
+ }
123
+ }));
124
+ const filteredSeries = useMemo(() => {
125
+ var _series$filter;
126
+ return (_series$filter = series == null ? void 0 : series.filter(s => seriesIds.includes(s.id))) != null ? _series$filter : [];
127
+ }, [series, seriesIds]);
128
+ const dataIndex = useDerivedValue(() => {
129
+ var _scrubberPosition$val;
130
+ return (_scrubberPosition$val = scrubberPosition.value) != null ? _scrubberPosition$val : Math.max(0, dataLength - 1);
131
+ }, [scrubberPosition, dataLength]);
132
+ const dataX = useDerivedValue(() => {
133
+ // Convert index to actual x value if axis has data
134
+ if (xAxis != null && xAxis.data && Array.isArray(xAxis.data) && xAxis.data[dataIndex.value] !== undefined) {
135
+ const dataValue = xAxis.data[dataIndex.value];
136
+ return typeof dataValue === 'string' ? dataIndex.value : dataValue;
137
+ }
138
+ return dataIndex.value;
139
+ }, [xAxis, dataIndex]);
140
+ const isIdle = useDerivedValue(() => {
141
+ return scrubberPosition.value === undefined;
142
+ }, [scrubberPosition]);
143
+ const createBeaconRef = useCallback(seriesId => {
144
+ return beaconRef => {
145
+ if (beaconRef) {
146
+ ScrubberBeaconRefs.registerRef(seriesId, beaconRef);
147
+ }
148
+ };
149
+ }, [ScrubberBeaconRefs]);
150
+ return filteredSeries.map(s => /*#__PURE__*/_jsx(BeaconWithData, {
151
+ BeaconComponent: BeaconComponent,
152
+ animate: animate,
153
+ beaconRef: createBeaconRef(s.id),
154
+ dataIndex: dataIndex,
155
+ dataX: dataX,
156
+ idlePulse: idlePulse,
157
+ isIdle: isIdle,
158
+ seriesId: s.id,
159
+ transitions: transitions
160
+ }, s.id));
161
+ }));
@@ -0,0 +1,185 @@
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 { memo, useCallback, useMemo, useState } from 'react';
3
+ import { useDerivedValue } from 'react-native-reanimated';
4
+ import { useCartesianChartContext } from '../ChartProvider';
5
+ import { applySerializableScale, useScrubberContext } from '../utils';
6
+ import { calculateLabelYPositions, getLabelPosition } from '../utils/scrubber';
7
+ import { DefaultScrubberBeaconLabel } from './DefaultScrubberBeaconLabel';
8
+ import { jsx as _jsx } from "react/jsx-runtime";
9
+ const PositionedLabel = /*#__PURE__*/memo(_ref => {
10
+ let {
11
+ index,
12
+ positions,
13
+ position,
14
+ label,
15
+ color,
16
+ seriesId,
17
+ onDimensionsChange,
18
+ BeaconLabelComponent,
19
+ labelHorizontalOffset,
20
+ labelFont
21
+ } = _ref;
22
+ const opacity = useDerivedValue(() => positions.value[index] !== null ? 1 : 0, [positions, index]);
23
+ const x = useDerivedValue(() => {
24
+ var _positions$value$inde, _positions$value$inde2;
25
+ return (_positions$value$inde = (_positions$value$inde2 = positions.value[index]) == null ? void 0 : _positions$value$inde2.x) != null ? _positions$value$inde : 0;
26
+ }, [positions, index]);
27
+ const y = useDerivedValue(() => {
28
+ var _positions$value$inde3, _positions$value$inde4;
29
+ return (_positions$value$inde3 = (_positions$value$inde4 = positions.value[index]) == null ? void 0 : _positions$value$inde4.y) != null ? _positions$value$inde3 : 0;
30
+ }, [positions, index]);
31
+ const dx = useDerivedValue(() => {
32
+ return position.value === 'right' ? labelHorizontalOffset : -labelHorizontalOffset;
33
+ }, [position, labelHorizontalOffset]);
34
+ const horizontalAlignment = useDerivedValue(() => position.value === 'right' ? 'left' : 'right', [position]);
35
+ return /*#__PURE__*/_jsx(BeaconLabelComponent, {
36
+ color: color,
37
+ dx: dx,
38
+ font: labelFont,
39
+ horizontalAlignment: horizontalAlignment,
40
+ label: label,
41
+ onDimensionsChange: d => onDimensionsChange(seriesId, d),
42
+ opacity: opacity,
43
+ seriesId: seriesId,
44
+ x: x,
45
+ y: y
46
+ });
47
+ });
48
+ export const ScrubberBeaconLabelGroup = /*#__PURE__*/memo(_ref2 => {
49
+ let {
50
+ labels,
51
+ labelMinGap = 4,
52
+ labelHorizontalOffset = 16,
53
+ labelFont,
54
+ BeaconLabelComponent = DefaultScrubberBeaconLabel
55
+ } = _ref2;
56
+ const {
57
+ getSeries,
58
+ getSeriesData,
59
+ getXSerializableScale,
60
+ getYSerializableScale,
61
+ getXAxis,
62
+ drawingArea,
63
+ dataLength
64
+ } = useCartesianChartContext();
65
+ const {
66
+ scrubberPosition
67
+ } = useScrubberContext();
68
+ const [labelDimensions, setLabelDimensions] = useState({});
69
+ const handleDimensionsChange = useCallback((id, dimensions) => {
70
+ setLabelDimensions(prev => {
71
+ const existing = prev[id];
72
+ if (existing && existing.width === dimensions.width && existing.height === dimensions.height) {
73
+ return prev;
74
+ }
75
+ return _extends({}, prev, {
76
+ [id]: dimensions
77
+ });
78
+ });
79
+ }, []);
80
+ const seriesInfo = useMemo(() => {
81
+ return labels.map(label => {
82
+ const series = getSeries(label.seriesId);
83
+ if (!series) return null;
84
+ const sourceData = getSeriesData(label.seriesId);
85
+ const yScale = getYSerializableScale(series.yAxisId);
86
+ return {
87
+ seriesId: label.seriesId,
88
+ sourceData,
89
+ yScale
90
+ };
91
+ }).filter(info => info !== null);
92
+ }, [labels, getSeries, getSeriesData, getYSerializableScale]);
93
+ const xScale = getXSerializableScale();
94
+ const xAxis = getXAxis();
95
+ const dataIndex = useDerivedValue(() => {
96
+ var _scrubberPosition$val;
97
+ return (_scrubberPosition$val = scrubberPosition.value) != null ? _scrubberPosition$val : Math.max(0, dataLength - 1);
98
+ }, [scrubberPosition, dataLength]);
99
+ const dataX = useDerivedValue(() => {
100
+ if (xAxis != null && xAxis.data && Array.isArray(xAxis.data) && xAxis.data[dataIndex.value] !== undefined) {
101
+ const dataValue = xAxis.data[dataIndex.value];
102
+ return typeof dataValue === 'string' ? dataIndex.value : dataValue;
103
+ }
104
+ return dataIndex.value;
105
+ }, [xAxis, dataIndex]);
106
+ const allLabelPositions = useDerivedValue(() => {
107
+ const sharedPixelX = dataX.value !== undefined && xScale ? applySerializableScale(dataX.value, xScale) : 0;
108
+ const desiredPositions = seriesInfo.map(info => {
109
+ let dataY;
110
+ if (xScale && info.yScale) {
111
+ if (info.sourceData && dataIndex.value !== undefined && dataIndex.value >= 0 && dataIndex.value < info.sourceData.length) {
112
+ const dataValue = info.sourceData[dataIndex.value];
113
+ if (Array.isArray(dataValue)) {
114
+ const validValues = dataValue.filter(val => val !== null);
115
+ if (validValues.length >= 1) {
116
+ dataY = validValues[validValues.length - 1];
117
+ }
118
+ }
119
+ }
120
+ }
121
+ if (dataY !== undefined && info.yScale) {
122
+ return {
123
+ seriesId: info.seriesId,
124
+ x: sharedPixelX,
125
+ desiredY: applySerializableScale(dataY, info.yScale)
126
+ };
127
+ }
128
+
129
+ // Return null for invalid data
130
+ return null;
131
+ });
132
+ const maxLabelHeight = Math.max(...Object.values(labelDimensions).map(dim => dim.height));
133
+ const maxLabelWidth = Math.max(...Object.values(labelDimensions).map(dim => dim.width));
134
+ const validPositions = desiredPositions.filter(pos => pos !== null);
135
+
136
+ // Convert to LabelDimension format expected by utility
137
+ const dimensions = validPositions.map(pos => {
138
+ var _trackedDimensions$wi, _trackedDimensions$he;
139
+ const trackedDimensions = labelDimensions[pos.seriesId];
140
+ return {
141
+ seriesId: pos.seriesId,
142
+ width: (_trackedDimensions$wi = trackedDimensions == null ? void 0 : trackedDimensions.width) != null ? _trackedDimensions$wi : maxLabelWidth,
143
+ height: (_trackedDimensions$he = trackedDimensions == null ? void 0 : trackedDimensions.height) != null ? _trackedDimensions$he : maxLabelHeight,
144
+ preferredX: pos.x,
145
+ preferredY: pos.desiredY
146
+ };
147
+ });
148
+
149
+ // Calculate Y positions with collision resolution for valid positions only
150
+ const yPositions = calculateLabelYPositions(dimensions, drawingArea, maxLabelHeight, labelMinGap);
151
+
152
+ // Return all positions (including null ones)
153
+ return desiredPositions.map(pos => {
154
+ var _yPositions$get;
155
+ if (!pos) return null;
156
+ return {
157
+ seriesId: pos.seriesId,
158
+ x: pos.x,
159
+ y: (_yPositions$get = yPositions.get(pos.seriesId)) != null ? _yPositions$get : pos.desiredY
160
+ };
161
+ });
162
+ }, [seriesInfo, dataIndex, dataX, xScale, labelDimensions, labelMinGap]);
163
+ const currentPosition = useDerivedValue(() => {
164
+ const pixelX = dataX.value !== undefined && xScale ? applySerializableScale(dataX.value, xScale) : 0;
165
+ const maxWidth = Math.max(...Object.values(labelDimensions).map(dim => dim.width));
166
+ const position = getLabelPosition(pixelX, maxWidth, drawingArea, labelHorizontalOffset);
167
+ return position;
168
+ }, [dataX, xScale, labelDimensions, drawingArea, labelHorizontalOffset]);
169
+ return seriesInfo.map((info, index) => {
170
+ const labelInfo = labels.find(label => label.seriesId === info.seriesId);
171
+ if (!labelInfo) return;
172
+ return /*#__PURE__*/_jsx(PositionedLabel, {
173
+ BeaconLabelComponent: BeaconLabelComponent,
174
+ color: labelInfo.color,
175
+ index: index,
176
+ label: labelInfo.label,
177
+ labelFont: labelFont,
178
+ labelHorizontalOffset: labelHorizontalOffset,
179
+ onDimensionsChange: handleDimensionsChange,
180
+ position: currentPosition,
181
+ positions: allLabelPositions,
182
+ seriesId: info.seriesId
183
+ }, info.seriesId);
184
+ });
185
+ });
@@ -0,0 +1,135 @@
1
+ import React, { useCallback, useMemo } from 'react';
2
+ import { Platform } from 'react-native';
3
+ import { Gesture, GestureDetector } from 'react-native-gesture-handler';
4
+ import { runOnJS, useAnimatedReaction, useSharedValue } from 'react-native-reanimated';
5
+ import { Haptics } from '@coinbase/cds-mobile/utils/haptics';
6
+ import { useCartesianChartContext } from '../ChartProvider';
7
+ import { invertSerializableScale, ScrubberContext } from '../utils';
8
+ import { getPointOnSerializableScale } from '../utils/point';
9
+ import { jsx as _jsx } from "react/jsx-runtime";
10
+ /**
11
+ * A component which encapsulates the ScrubberContext.
12
+ * It depends on a ChartContext in order to provide accurate touch tracking.
13
+ */
14
+ export const ScrubberProvider = _ref => {
15
+ let {
16
+ children,
17
+ enableScrubbing,
18
+ onScrubberPositionChange,
19
+ allowOverflowGestures
20
+ } = _ref;
21
+ const chartContext = useCartesianChartContext();
22
+ if (!chartContext) {
23
+ throw new Error('ScrubberProvider must be used within a ChartContext');
24
+ }
25
+ const {
26
+ getXSerializableScale,
27
+ getXAxis
28
+ } = chartContext;
29
+ const scrubberPosition = useSharedValue(undefined);
30
+ const xAxis = useMemo(() => getXAxis(), [getXAxis]);
31
+ const xScale = useMemo(() => getXSerializableScale(), [getXSerializableScale]);
32
+ const getDataIndexFromX = useCallback(touchX => {
33
+ 'worklet';
34
+
35
+ if (!xScale || !xAxis) return 0;
36
+ if (xScale.type === 'band') {
37
+ const [domainMin, domainMax] = xScale.domain;
38
+ const categoryCount = domainMax - domainMin + 1;
39
+ let closestIndex = 0;
40
+ let closestDistance = Infinity;
41
+ for (let i = 0; i < categoryCount; i++) {
42
+ const xPos = getPointOnSerializableScale(i, xScale);
43
+ if (xPos !== undefined) {
44
+ const distance = Math.abs(touchX - xPos);
45
+ if (distance < closestDistance) {
46
+ closestDistance = distance;
47
+ closestIndex = i;
48
+ }
49
+ }
50
+ }
51
+ return closestIndex;
52
+ } else {
53
+ // For numeric scales with axis data, find the nearest data point
54
+ const axisData = xAxis.data;
55
+ if (axisData && Array.isArray(axisData) && typeof axisData[0] === 'number') {
56
+ // We have numeric axis data - find the closest data point
57
+ const numericData = axisData;
58
+ let closestIndex = 0;
59
+ let closestDistance = Infinity;
60
+ for (let i = 0; i < numericData.length; i++) {
61
+ const xValue = numericData[i];
62
+ const xPos = getPointOnSerializableScale(xValue, xScale);
63
+ if (xPos !== undefined) {
64
+ const distance = Math.abs(touchX - xPos);
65
+ if (distance < closestDistance) {
66
+ closestDistance = distance;
67
+ closestIndex = i;
68
+ }
69
+ }
70
+ }
71
+ return closestIndex;
72
+ } else {
73
+ var _domain$min, _domain$max;
74
+ const xValue = invertSerializableScale(touchX, xScale);
75
+ const dataIndex = Math.round(xValue);
76
+ const domain = xAxis.domain;
77
+ return Math.max((_domain$min = domain.min) != null ? _domain$min : 0, Math.min(dataIndex, (_domain$max = domain.max) != null ? _domain$max : 0));
78
+ }
79
+ }
80
+ }, [xAxis, xScale]);
81
+ const handleStartEndHaptics = useCallback(() => {
82
+ void Haptics.lightImpact();
83
+ }, []);
84
+ useAnimatedReaction(() => scrubberPosition.value, (currentValue, previousValue) => {
85
+ // Confirm changes here and inside of our gesture handler before calling JS thread
86
+ // To prevent any rerenders
87
+ if (onScrubberPositionChange !== undefined && currentValue !== previousValue) {
88
+ runOnJS(onScrubberPositionChange)(currentValue);
89
+ }
90
+ }, [onScrubberPositionChange]);
91
+
92
+ // Create the long press pan gesture
93
+ const longPressGesture = useMemo(() => Gesture.Pan().activateAfterLongPress(110).shouldCancelWhenOutside(!allowOverflowGestures).onStart(function onStart(event) {
94
+ runOnJS(handleStartEndHaptics)();
95
+
96
+ // Android does not trigger onUpdate when the gesture starts. This achieves consistent behavior across both iOS and Android
97
+ if (Platform.OS === 'android') {
98
+ const newScrubberPosition = getDataIndexFromX(event.x);
99
+ if (newScrubberPosition !== scrubberPosition.value) {
100
+ scrubberPosition.value = newScrubberPosition;
101
+ }
102
+ }
103
+ }).onUpdate(function onUpdate(event) {
104
+ const newScrubberPosition = getDataIndexFromX(event.x);
105
+ if (newScrubberPosition !== scrubberPosition.value) {
106
+ scrubberPosition.value = newScrubberPosition;
107
+ }
108
+ }).onEnd(function onEnd() {
109
+ if (enableScrubbing) {
110
+ runOnJS(handleStartEndHaptics)();
111
+ scrubberPosition.value = undefined;
112
+ }
113
+ }).onTouchesCancelled(function onTouchesCancelled() {
114
+ if (enableScrubbing) {
115
+ scrubberPosition.value = undefined;
116
+ }
117
+ }), [allowOverflowGestures, handleStartEndHaptics, getDataIndexFromX, scrubberPosition, enableScrubbing]);
118
+ const contextValue = useMemo(() => ({
119
+ enableScrubbing: !!enableScrubbing,
120
+ scrubberPosition
121
+ }), [enableScrubbing, scrubberPosition]);
122
+ const content = /*#__PURE__*/_jsx(ScrubberContext.Provider, {
123
+ value: contextValue,
124
+ children: children
125
+ });
126
+
127
+ // Wrap with gesture handler only if scrubbing is enabled
128
+ if (enableScrubbing) {
129
+ return /*#__PURE__*/_jsx(GestureDetector, {
130
+ gesture: longPressGesture,
131
+ children: content
132
+ });
133
+ }
134
+ return content;
135
+ };
@@ -0,0 +1,4 @@
1
+ export * from './DefaultScrubberBeacon';
2
+ export * from './DefaultScrubberBeaconLabel';
3
+ export * from './DefaultScrubberLabel';
4
+ export * from './Scrubber';