@coinbase/cds-web-visualization 3.3.0 → 3.4.0-beta.1

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 (204) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/dts/chart/CartesianChart.d.ts +36 -0
  3. package/dts/chart/CartesianChart.d.ts.map +1 -0
  4. package/dts/chart/ChartProvider.d.ts +6 -0
  5. package/dts/chart/ChartProvider.d.ts.map +1 -0
  6. package/dts/chart/Path.d.ts +34 -0
  7. package/dts/chart/Path.d.ts.map +1 -0
  8. package/dts/chart/PeriodSelector.d.ts +61 -0
  9. package/dts/chart/PeriodSelector.d.ts.map +1 -0
  10. package/dts/chart/Point.d.ts +153 -0
  11. package/dts/chart/Point.d.ts.map +1 -0
  12. package/dts/chart/area/Area.d.ts +48 -0
  13. package/dts/chart/area/Area.d.ts.map +1 -0
  14. package/dts/chart/area/AreaChart.d.ts +52 -0
  15. package/dts/chart/area/AreaChart.d.ts.map +1 -0
  16. package/dts/chart/area/DottedArea.d.ts +68 -0
  17. package/dts/chart/area/DottedArea.d.ts.map +1 -0
  18. package/dts/chart/area/GradientArea.d.ts +30 -0
  19. package/dts/chart/area/GradientArea.d.ts.map +1 -0
  20. package/dts/chart/area/SolidArea.d.ts +8 -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 +208 -0
  25. package/dts/chart/axis/Axis.d.ts.map +1 -0
  26. package/dts/chart/axis/XAxis.d.ts +16 -0
  27. package/dts/chart/axis/XAxis.d.ts.map +1 -0
  28. package/dts/chart/axis/YAxis.d.ts +21 -0
  29. package/dts/chart/axis/YAxis.d.ts.map +1 -0
  30. package/dts/chart/axis/index.d.ts +4 -0
  31. package/dts/chart/axis/index.d.ts.map +1 -0
  32. package/dts/chart/bar/Bar.d.ts +91 -0
  33. package/dts/chart/bar/Bar.d.ts.map +1 -0
  34. package/dts/chart/bar/BarChart.d.ts +53 -0
  35. package/dts/chart/bar/BarChart.d.ts.map +1 -0
  36. package/dts/chart/bar/BarPlot.d.ts +29 -0
  37. package/dts/chart/bar/BarPlot.d.ts.map +1 -0
  38. package/dts/chart/bar/BarStack.d.ts +111 -0
  39. package/dts/chart/bar/BarStack.d.ts.map +1 -0
  40. package/dts/chart/bar/BarStackGroup.d.ts +35 -0
  41. package/dts/chart/bar/BarStackGroup.d.ts.map +1 -0
  42. package/dts/chart/bar/DefaultBar.d.ts +17 -0
  43. package/dts/chart/bar/DefaultBar.d.ts.map +1 -0
  44. package/dts/chart/bar/DefaultBarStack.d.ts +16 -0
  45. package/dts/chart/bar/DefaultBarStack.d.ts.map +1 -0
  46. package/dts/chart/bar/index.d.ts +8 -0
  47. package/dts/chart/bar/index.d.ts.map +1 -0
  48. package/dts/chart/index.d.ts +13 -0
  49. package/dts/chart/index.d.ts.map +1 -0
  50. package/dts/chart/line/DottedLine.d.ts +14 -0
  51. package/dts/chart/line/DottedLine.d.ts.map +1 -0
  52. package/dts/chart/line/GradientLine.d.ts +42 -0
  53. package/dts/chart/line/GradientLine.d.ts.map +1 -0
  54. package/dts/chart/line/Line.d.ts +80 -0
  55. package/dts/chart/line/Line.d.ts.map +1 -0
  56. package/dts/chart/line/LineChart.d.ts +59 -0
  57. package/dts/chart/line/LineChart.d.ts.map +1 -0
  58. package/dts/chart/line/ReferenceLine.d.ts +131 -0
  59. package/dts/chart/line/ReferenceLine.d.ts.map +1 -0
  60. package/dts/chart/line/SolidLine.d.ts +14 -0
  61. package/dts/chart/line/SolidLine.d.ts.map +1 -0
  62. package/dts/chart/line/index.d.ts +7 -0
  63. package/dts/chart/line/index.d.ts.map +1 -0
  64. package/dts/chart/scrubber/Scrubber.d.ts +149 -0
  65. package/dts/chart/scrubber/Scrubber.d.ts.map +1 -0
  66. package/dts/chart/scrubber/ScrubberBeacon.d.ts +93 -0
  67. package/dts/chart/scrubber/ScrubberBeacon.d.ts.map +1 -0
  68. package/dts/chart/scrubber/ScrubberBeaconLabel.d.ts +7 -0
  69. package/dts/chart/scrubber/ScrubberBeaconLabel.d.ts.map +1 -0
  70. package/dts/chart/scrubber/ScrubberProvider.d.ts +17 -0
  71. package/dts/chart/scrubber/ScrubberProvider.d.ts.map +1 -0
  72. package/dts/chart/scrubber/index.d.ts +2 -0
  73. package/dts/chart/scrubber/index.d.ts.map +1 -0
  74. package/dts/chart/text/ChartText.d.ts +114 -0
  75. package/dts/chart/text/ChartText.d.ts.map +1 -0
  76. package/dts/chart/text/SmartChartTextGroup.d.ts +55 -0
  77. package/dts/chart/text/SmartChartTextGroup.d.ts.map +1 -0
  78. package/dts/chart/text/index.d.ts +3 -0
  79. package/dts/chart/text/index.d.ts.map +1 -0
  80. package/dts/chart/utils/axis.d.ts +342 -0
  81. package/dts/chart/utils/axis.d.ts.map +1 -0
  82. package/dts/chart/utils/bar.d.ts +20 -0
  83. package/dts/chart/utils/bar.d.ts.map +1 -0
  84. package/dts/chart/utils/chart.d.ts +97 -0
  85. package/dts/chart/utils/chart.d.ts.map +1 -0
  86. package/dts/chart/utils/context.d.ts +95 -0
  87. package/dts/chart/utils/context.d.ts.map +1 -0
  88. package/dts/chart/utils/index.d.ts +8 -0
  89. package/dts/chart/utils/index.d.ts.map +1 -0
  90. package/dts/chart/utils/path.d.ts +107 -0
  91. package/dts/chart/utils/path.d.ts.map +1 -0
  92. package/dts/chart/utils/point.d.ts +75 -0
  93. package/dts/chart/utils/point.d.ts.map +1 -0
  94. package/dts/chart/utils/scale.d.ts +43 -0
  95. package/dts/chart/utils/scale.d.ts.map +1 -0
  96. package/dts/index.d.ts +2 -1
  97. package/dts/index.d.ts.map +1 -1
  98. package/dts/sparkline/Counter.d.ts +7 -2
  99. package/dts/sparkline/Sparkline.d.ts +61 -16
  100. package/dts/sparkline/Sparkline.d.ts.map +1 -1
  101. package/dts/sparkline/SparklineArea.d.ts +12 -4
  102. package/dts/sparkline/SparklineArea.d.ts.map +1 -1
  103. package/dts/sparkline/SparklineAreaPattern.d.ts +12 -4
  104. package/dts/sparkline/SparklineAreaPattern.d.ts.map +1 -1
  105. package/dts/sparkline/SparklineGradient.d.ts +21 -10
  106. package/dts/sparkline/SparklineGradient.d.ts.map +1 -1
  107. package/dts/sparkline/SparklinePath.d.ts +8 -6
  108. package/dts/sparkline/__figma__/Sparkline.figma.d.ts +1 -1
  109. package/dts/sparkline/generateSparklineWithId.d.ts +8 -2
  110. package/dts/sparkline/generateSparklineWithId.d.ts.map +1 -1
  111. package/dts/sparkline/index.d.ts +1 -1
  112. package/dts/sparkline/sparkline-interactive/InnerSparklineInteractiveProvider.d.ts +9 -5
  113. package/dts/sparkline/sparkline-interactive/SparklineInteractive.d.ts +168 -118
  114. package/dts/sparkline/sparkline-interactive/SparklineInteractive.d.ts.map +1 -1
  115. package/dts/sparkline/sparkline-interactive/SparklineInteractiveAnimatedPath.d.ts +22 -9
  116. package/dts/sparkline/sparkline-interactive/SparklineInteractiveAnimatedPath.d.ts.map +1 -1
  117. package/dts/sparkline/sparkline-interactive/SparklineInteractiveHoverDate.d.ts +4 -2
  118. package/dts/sparkline/sparkline-interactive/SparklineInteractiveHoverPrice.d.ts +4 -2
  119. package/dts/sparkline/sparkline-interactive/SparklineInteractiveLineVertical.d.ts +5 -3
  120. package/dts/sparkline/sparkline-interactive/SparklineInteractiveMarkerDates.d.ts +11 -6
  121. package/dts/sparkline/sparkline-interactive/SparklineInteractivePaths.d.ts +21 -7
  122. package/dts/sparkline/sparkline-interactive/SparklineInteractivePaths.d.ts.map +1 -1
  123. package/dts/sparkline/sparkline-interactive/SparklineInteractivePeriodSelector.d.ts +21 -16
  124. package/dts/sparkline/sparkline-interactive/SparklineInteractiveProvider.d.ts +17 -12
  125. package/dts/sparkline/sparkline-interactive/SparklineInteractiveScrubHandler.d.ts +23 -10
  126. package/dts/sparkline/sparkline-interactive/SparklineInteractiveScrubProvider.d.ts +12 -12
  127. package/dts/sparkline/sparkline-interactive/SparklineInteractiveTimeseriesPaths.d.ts +22 -14
  128. package/dts/sparkline/sparkline-interactive/__figma__/SparklineInteractive.figma.d.ts +1 -1
  129. package/dts/sparkline/sparkline-interactive/fade.d.ts +1 -1
  130. package/dts/sparkline/sparkline-interactive/useSparklineInteractiveConstants.d.ts +11 -11
  131. package/dts/sparkline/sparkline-interactive-header/SparklineInteractiveHeader.d.ts +101 -93
  132. package/dts/sparkline/sparkline-interactive-header/__figma__/SparklineInteractiveHeader.figma.d.ts +1 -1
  133. package/esm/chart/CartesianChart.css +1 -0
  134. package/esm/chart/CartesianChart.js +258 -0
  135. package/esm/chart/ChartProvider.js +10 -0
  136. package/esm/chart/Path.js +89 -0
  137. package/esm/chart/PeriodSelector.css +1 -0
  138. package/esm/chart/PeriodSelector.js +126 -0
  139. package/esm/chart/Point.css +2 -0
  140. package/esm/chart/Point.js +171 -0
  141. package/esm/chart/area/Area.js +85 -0
  142. package/esm/chart/area/AreaChart.js +164 -0
  143. package/esm/chart/area/DottedArea.js +141 -0
  144. package/esm/chart/area/GradientArea.js +111 -0
  145. package/esm/chart/area/SolidArea.js +29 -0
  146. package/esm/chart/area/index.js +7 -0
  147. package/esm/chart/axis/Axis.js +46 -0
  148. package/esm/chart/axis/XAxis.css +2 -0
  149. package/esm/chart/axis/XAxis.js +195 -0
  150. package/esm/chart/axis/YAxis.css +2 -0
  151. package/esm/chart/axis/YAxis.js +183 -0
  152. package/esm/chart/axis/index.js +5 -0
  153. package/esm/chart/bar/Bar.js +59 -0
  154. package/esm/chart/bar/BarChart.js +147 -0
  155. package/esm/chart/bar/BarPlot.js +96 -0
  156. package/esm/chart/bar/BarStack.js +519 -0
  157. package/esm/chart/bar/BarStackGroup.js +96 -0
  158. package/esm/chart/bar/DefaultBar.js +64 -0
  159. package/esm/chart/bar/DefaultBarStack.js +60 -0
  160. package/esm/chart/bar/index.js +9 -0
  161. package/esm/chart/index.js +14 -0
  162. package/esm/chart/line/DottedLine.js +38 -0
  163. package/esm/chart/line/GradientLine.js +58 -0
  164. package/esm/chart/line/Line.js +159 -0
  165. package/esm/chart/line/LineChart.js +120 -0
  166. package/esm/chart/line/ReferenceLine.js +142 -0
  167. package/esm/chart/line/SolidLine.js +34 -0
  168. package/esm/chart/line/index.js +8 -0
  169. package/esm/chart/scrubber/Scrubber.js +483 -0
  170. package/esm/chart/scrubber/ScrubberBeacon.js +195 -0
  171. package/esm/chart/scrubber/ScrubberBeaconLabel.js +33 -0
  172. package/esm/chart/scrubber/ScrubberProvider.js +228 -0
  173. package/esm/chart/scrubber/index.js +2 -0
  174. package/esm/chart/text/ChartText.js +236 -0
  175. package/esm/chart/text/SmartChartTextGroup.js +226 -0
  176. package/esm/chart/text/index.js +4 -0
  177. package/esm/chart/utils/axis.js +593 -0
  178. package/esm/chart/utils/bar.js +24 -0
  179. package/esm/chart/utils/chart.js +229 -0
  180. package/esm/chart/utils/context.js +15 -0
  181. package/esm/chart/utils/index.js +9 -0
  182. package/esm/chart/utils/path.js +204 -0
  183. package/esm/chart/utils/point.js +118 -0
  184. package/esm/chart/utils/scale.js +48 -0
  185. package/esm/index.js +4 -1
  186. package/esm/sparkline/Sparkline.js +129 -15
  187. package/esm/sparkline/SparklineArea.js +7 -2
  188. package/esm/sparkline/SparklineAreaPattern.js +4 -2
  189. package/esm/sparkline/SparklineGradient.js +16 -58
  190. package/esm/sparkline/generateSparklineWithId.js +3 -2
  191. package/esm/sparkline/sparkline-interactive/SparklineInteractive.js +5 -1
  192. package/esm/sparkline/sparkline-interactive/SparklineInteractiveAnimatedPath.js +5 -2
  193. package/esm/sparkline/sparkline-interactive/SparklineInteractivePaths.js +4 -0
  194. package/package.json +15 -11
  195. package/dts/sparkline/sparkline-interactive/__stories__/SparklineInteractive.stories.d.ts +0 -374
  196. package/dts/sparkline/sparkline-interactive/__stories__/SparklineInteractive.stories.d.ts.map +0 -1
  197. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractive.test.d.ts +0 -2
  198. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractive.test.d.ts.map +0 -1
  199. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractivePeriodSelector.test.d.ts +0 -2
  200. package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractivePeriodSelector.test.d.ts.map +0 -1
  201. package/dts/sparkline/sparkline-interactive-header/__stories__/SparklineInteractiveHeader.stories.d.ts +0 -87
  202. package/dts/sparkline/sparkline-interactive-header/__stories__/SparklineInteractiveHeader.stories.d.ts.map +0 -1
  203. package/dts/sparkline/sparkline-interactive-header/__tests__/SparklineInteractiveHeader.test.d.ts +0 -2
  204. package/dts/sparkline/sparkline-interactive-header/__tests__/SparklineInteractiveHeader.test.d.ts.map +0 -1
@@ -0,0 +1,33 @@
1
+ const _excluded = ["background", "color", "elevation", "borderRadius", "font", "verticalAlignment"];
2
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
5
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
6
+ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
7
+ function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
8
+ 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; }
9
+ import { memo } from 'react';
10
+ import { ChartText } from '../text';
11
+ import { jsx as _jsx } from "react/jsx-runtime";
12
+ /**
13
+ * The ScrubberBeaconLabel is a special instance of ChartText used to label a series' scrubber beacon (i.e. a point on the series pinned to the scrubber position).
14
+ */
15
+ export const ScrubberBeaconLabel = /*#__PURE__*/memo(_ref => {
16
+ let {
17
+ background = 'white',
18
+ color = 'var(--color-fgPrimary)',
19
+ elevation = background !== undefined ? 1 : undefined,
20
+ borderRadius = background !== undefined ? 4 : undefined,
21
+ font = 'label1',
22
+ verticalAlignment = 'middle'
23
+ } = _ref,
24
+ chartTextProps = _objectWithoutProperties(_ref, _excluded);
25
+ return /*#__PURE__*/_jsx(ChartText, _objectSpread({
26
+ background: background,
27
+ borderRadius: borderRadius,
28
+ color: color,
29
+ elevation: elevation,
30
+ font: font,
31
+ verticalAlignment: verticalAlignment
32
+ }, chartTextProps));
33
+ });
@@ -0,0 +1,228 @@
1
+ import React, { useCallback, useEffect, useMemo, useState } from 'react';
2
+ import { useCartesianChartContext } from '../ChartProvider';
3
+ import { isCategoricalScale, ScrubberContext } from '../utils';
4
+ import { jsx as _jsx } from "react/jsx-runtime";
5
+ /**
6
+ * A component which encapsulates the ScrubberContext.
7
+ * It depends on a ChartContext in order to provide accurate mouse tracking.
8
+ */
9
+ export const ScrubberProvider = _ref => {
10
+ let {
11
+ children,
12
+ svgRef,
13
+ enableScrubbing,
14
+ onScrubberPositionChange
15
+ } = _ref;
16
+ const chartContext = useCartesianChartContext();
17
+ if (!chartContext) {
18
+ throw new Error('ScrubberProvider must be used within a ChartContext');
19
+ }
20
+ const {
21
+ getXScale,
22
+ getXAxis,
23
+ series
24
+ } = chartContext;
25
+ const [scrubberPosition, setScrubberPosition] = useState(undefined);
26
+ const getDataIndexFromX = useCallback(mouseX => {
27
+ const xScale = getXScale();
28
+ const xAxis = getXAxis();
29
+ if (!xScale || !xAxis) return 0;
30
+ if (isCategoricalScale(xScale)) {
31
+ var _ref2, _xScale$domain, _xScale$domain2, _xScale$bandwidth, _xScale$bandwidth2;
32
+ const categories = (_ref2 = (_xScale$domain = (_xScale$domain2 = xScale.domain) === null || _xScale$domain2 === void 0 ? void 0 : _xScale$domain2.call(xScale)) !== null && _xScale$domain !== void 0 ? _xScale$domain : xAxis.data) !== null && _ref2 !== void 0 ? _ref2 : [];
33
+ const bandwidth = (_xScale$bandwidth = (_xScale$bandwidth2 = xScale.bandwidth) === null || _xScale$bandwidth2 === void 0 ? void 0 : _xScale$bandwidth2.call(xScale)) !== null && _xScale$bandwidth !== void 0 ? _xScale$bandwidth : 0;
34
+ let closestIndex = 0;
35
+ let closestDistance = Infinity;
36
+ for (let i = 0; i < categories.length; i++) {
37
+ const xPos = xScale(i);
38
+ if (xPos !== undefined) {
39
+ const distance = Math.abs(mouseX - (xPos + bandwidth / 2));
40
+ if (distance < closestDistance) {
41
+ closestDistance = distance;
42
+ closestIndex = i;
43
+ }
44
+ }
45
+ }
46
+ return closestIndex;
47
+ } else {
48
+ // For numeric scales with axis data, find the nearest data point
49
+ const axisData = xAxis.data;
50
+ if (axisData && Array.isArray(axisData) && typeof axisData[0] === 'number') {
51
+ // We have numeric axis data - find the closest data point
52
+ const numericData = axisData;
53
+ let closestIndex = 0;
54
+ let closestDistance = Infinity;
55
+ for (let i = 0; i < numericData.length; i++) {
56
+ const xValue = numericData[i];
57
+ const xPos = xScale(xValue);
58
+ if (xPos !== undefined) {
59
+ const distance = Math.abs(mouseX - xPos);
60
+ if (distance < closestDistance) {
61
+ closestDistance = distance;
62
+ closestIndex = i;
63
+ }
64
+ }
65
+ }
66
+ return closestIndex;
67
+ } else {
68
+ var _domain$min, _domain$max;
69
+ const xValue = xScale.invert(mouseX);
70
+ const dataIndex = Math.round(xValue);
71
+ const domain = xAxis.domain;
72
+ return Math.max((_domain$min = domain.min) !== null && _domain$min !== void 0 ? _domain$min : 0, Math.min(dataIndex, (_domain$max = domain.max) !== null && _domain$max !== void 0 ? _domain$max : 0));
73
+ }
74
+ }
75
+ }, [getXScale, getXAxis]);
76
+ const handlePointerMove = useCallback((clientX, target) => {
77
+ if (!enableScrubbing || !series || series.length === 0) return;
78
+ const rect = target.getBoundingClientRect();
79
+ const x = clientX - rect.left;
80
+ const dataIndex = getDataIndexFromX(x);
81
+ if (dataIndex !== scrubberPosition) {
82
+ setScrubberPosition(dataIndex);
83
+ onScrubberPositionChange === null || onScrubberPositionChange === void 0 || onScrubberPositionChange(dataIndex);
84
+ }
85
+ }, [enableScrubbing, series, getDataIndexFromX, scrubberPosition, onScrubberPositionChange]);
86
+ const handleMouseMove = useCallback(event => {
87
+ const target = event.currentTarget;
88
+ handlePointerMove(event.clientX, target);
89
+ }, [handlePointerMove]);
90
+ const handleTouchMove = useCallback(event => {
91
+ if (!event.touches.length) return;
92
+ // Prevent scrolling while scrubbing
93
+ event.preventDefault();
94
+ const touch = event.touches[0];
95
+ const target = event.currentTarget;
96
+ handlePointerMove(touch.clientX, target);
97
+ }, [handlePointerMove]);
98
+ const handleTouchStart = useCallback(event => {
99
+ if (!enableScrubbing || !event.touches.length) return;
100
+ // Handle initial touch
101
+ const touch = event.touches[0];
102
+ const target = event.currentTarget;
103
+ handlePointerMove(touch.clientX, target);
104
+ }, [enableScrubbing, handlePointerMove]);
105
+ const handlePointerLeave = useCallback(() => {
106
+ if (!enableScrubbing) return;
107
+ setScrubberPosition(undefined);
108
+ onScrubberPositionChange === null || onScrubberPositionChange === void 0 || onScrubberPositionChange(undefined);
109
+ }, [enableScrubbing, onScrubberPositionChange]);
110
+ const handleMouseLeave = handlePointerLeave;
111
+ const handleTouchEnd = handlePointerLeave;
112
+ const handleKeyDown = useCallback(event => {
113
+ if (!enableScrubbing) return;
114
+ const xScale = getXScale();
115
+ const xAxis = getXAxis();
116
+ if (!xScale || !xAxis) return;
117
+ const isBand = isCategoricalScale(xScale);
118
+
119
+ // Determine the actual data indices we can navigate to
120
+ let minIndex;
121
+ let maxIndex;
122
+ let dataPoints;
123
+ if (isBand) {
124
+ var _ref3, _xScale$domain3, _xScale$domain4;
125
+ // For categorical scales, use the categories
126
+ const categories = (_ref3 = (_xScale$domain3 = (_xScale$domain4 = xScale.domain) === null || _xScale$domain4 === void 0 ? void 0 : _xScale$domain4.call(xScale)) !== null && _xScale$domain3 !== void 0 ? _xScale$domain3 : xAxis.data) !== null && _ref3 !== void 0 ? _ref3 : [];
127
+ minIndex = 0;
128
+ maxIndex = Math.max(0, categories.length - 1);
129
+ dataPoints = categories.length;
130
+ } else {
131
+ // For numeric scales, check if we have specific data points
132
+ const axisData = xAxis.data;
133
+ if (axisData && Array.isArray(axisData)) {
134
+ // We have specific data points - use their indices
135
+ minIndex = 0;
136
+ maxIndex = Math.max(0, axisData.length - 1);
137
+ dataPoints = axisData.length;
138
+ } else {
139
+ var _domain$min2, _domain$max2;
140
+ // Fall back to domain-based navigation for continuous scales without specific data
141
+ const domain = xAxis.domain;
142
+ minIndex = (_domain$min2 = domain.min) !== null && _domain$min2 !== void 0 ? _domain$min2 : 0;
143
+ maxIndex = (_domain$max2 = domain.max) !== null && _domain$max2 !== void 0 ? _domain$max2 : 0;
144
+ dataPoints = maxIndex - minIndex + 1;
145
+ }
146
+ }
147
+ const currentIndex = scrubberPosition !== null && scrubberPosition !== void 0 ? scrubberPosition : minIndex;
148
+ const dataRange = maxIndex - minIndex;
149
+
150
+ // Multi-step jump when shift is held (10% of data range, minimum 1, maximum 10)
151
+ const multiSkip = event.shiftKey;
152
+ const stepSize = multiSkip ? Math.min(10, Math.max(1, Math.floor(dataRange * 0.1))) : 1;
153
+ let newIndex;
154
+ switch (event.key) {
155
+ case 'ArrowLeft':
156
+ event.preventDefault();
157
+ newIndex = Math.max(minIndex, currentIndex - stepSize);
158
+ break;
159
+ case 'ArrowRight':
160
+ event.preventDefault();
161
+ newIndex = Math.min(maxIndex, currentIndex + stepSize);
162
+ break;
163
+ case 'Home':
164
+ event.preventDefault();
165
+ newIndex = minIndex;
166
+ break;
167
+ case 'End':
168
+ event.preventDefault();
169
+ newIndex = maxIndex;
170
+ break;
171
+ case 'Escape':
172
+ event.preventDefault();
173
+ newIndex = undefined; // Clear highlighting
174
+ break;
175
+ default:
176
+ return;
177
+ // Don't handle other keys
178
+ }
179
+ if (newIndex !== scrubberPosition) {
180
+ setScrubberPosition(newIndex);
181
+ onScrubberPositionChange === null || onScrubberPositionChange === void 0 || onScrubberPositionChange(newIndex);
182
+ }
183
+ }, [enableScrubbing, getXScale, getXAxis, scrubberPosition, onScrubberPositionChange]);
184
+ const handleBlur = useCallback(() => {
185
+ if (!enableScrubbing || scrubberPosition === undefined) return;
186
+ setScrubberPosition(undefined);
187
+ onScrubberPositionChange === null || onScrubberPositionChange === void 0 || onScrubberPositionChange(undefined);
188
+ }, [enableScrubbing, onScrubberPositionChange, scrubberPosition]);
189
+
190
+ // Attach event listeners to SVG element
191
+ useEffect(() => {
192
+ if (!(svgRef !== null && svgRef !== void 0 && svgRef.current) || !enableScrubbing) return;
193
+ const svg = svgRef.current;
194
+
195
+ // Add event listeners
196
+ svg.addEventListener('mousemove', handleMouseMove);
197
+ svg.addEventListener('mouseleave', handleMouseLeave);
198
+ svg.addEventListener('touchstart', handleTouchStart, {
199
+ passive: false
200
+ });
201
+ svg.addEventListener('touchmove', handleTouchMove, {
202
+ passive: false
203
+ });
204
+ svg.addEventListener('touchend', handleTouchEnd);
205
+ svg.addEventListener('touchcancel', handleTouchEnd);
206
+ svg.addEventListener('keydown', handleKeyDown);
207
+ svg.addEventListener('blur', handleBlur);
208
+ return () => {
209
+ svg.removeEventListener('mousemove', handleMouseMove);
210
+ svg.removeEventListener('mouseleave', handleMouseLeave);
211
+ svg.removeEventListener('touchstart', handleTouchStart);
212
+ svg.removeEventListener('touchmove', handleTouchMove);
213
+ svg.removeEventListener('touchend', handleTouchEnd);
214
+ svg.removeEventListener('touchcancel', handleTouchEnd);
215
+ svg.removeEventListener('keydown', handleKeyDown);
216
+ svg.removeEventListener('blur', handleBlur);
217
+ };
218
+ }, [svgRef, enableScrubbing, handleMouseMove, handleMouseLeave, handleTouchStart, handleTouchMove, handleTouchEnd, handleKeyDown, handleBlur]);
219
+ const contextValue = useMemo(() => ({
220
+ enableScrubbing: !!enableScrubbing,
221
+ scrubberPosition,
222
+ onScrubberPositionChange: setScrubberPosition
223
+ }), [enableScrubbing, scrubberPosition]);
224
+ return /*#__PURE__*/_jsx(ScrubberContext.Provider, {
225
+ value: contextValue,
226
+ children: children
227
+ });
228
+ };
@@ -0,0 +1,2 @@
1
+ // Only export Scrubber component
2
+ export * from './Scrubber';
@@ -0,0 +1,236 @@
1
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
2
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
3
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
4
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
5
+ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
6
+ import React, { memo, useEffect, useMemo, useRef, useState } from 'react';
7
+ import { cx } from '@coinbase/cds-web';
8
+ import { Box } from '@coinbase/cds-web/layout';
9
+ import { Text } from '@coinbase/cds-web/typography';
10
+ import { m as motion } from 'framer-motion';
11
+ import { useCartesianChartContext } from '../ChartProvider';
12
+ import { getChartInset } from '../utils';
13
+
14
+ /**
15
+ * The supported content types for ChartText.
16
+ */
17
+
18
+ /**
19
+ * Horizontal alignment options for chart text.
20
+ */
21
+
22
+ /**
23
+ * Vertical alignment options for chart text.
24
+ */
25
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
26
+ /**
27
+ * Get text anchor based on horizontal alignment.
28
+ */
29
+ const getTextAnchor = alignment => {
30
+ switch (alignment) {
31
+ case 'left':
32
+ return 'start';
33
+ case 'center':
34
+ return 'middle';
35
+ case 'right':
36
+ return 'end';
37
+ }
38
+ };
39
+
40
+ /**
41
+ * Get dominant baseline based on vertical alignment.
42
+ */
43
+ const getDominantBaseline = alignment => {
44
+ switch (alignment) {
45
+ case 'top':
46
+ return 'hanging';
47
+ case 'middle':
48
+ return 'central';
49
+ case 'bottom':
50
+ return 'ideographic';
51
+ }
52
+ };
53
+ export const ChartText = /*#__PURE__*/memo(_ref => {
54
+ let {
55
+ children,
56
+ x,
57
+ y,
58
+ horizontalAlignment = 'center',
59
+ verticalAlignment = 'middle',
60
+ dx,
61
+ dy,
62
+ disableRepositioning,
63
+ bounds,
64
+ opacity,
65
+ testID,
66
+ font = 'label2',
67
+ fontFamily,
68
+ fontSize,
69
+ fontWeight,
70
+ elevation,
71
+ color = 'var(--color-fgMuted)',
72
+ background = elevation && elevation > 0 ? 'var(--color-bg)' : 'transparent',
73
+ borderRadius,
74
+ inset: insetInput,
75
+ onDimensionsChange,
76
+ style,
77
+ styles,
78
+ className,
79
+ classNames
80
+ } = _ref;
81
+ const {
82
+ animate,
83
+ width: chartWidth,
84
+ height: chartHeight
85
+ } = useCartesianChartContext();
86
+ const fullChartBounds = useMemo(() => ({
87
+ x: 0,
88
+ y: 0,
89
+ width: chartWidth,
90
+ height: chartHeight
91
+ }), [chartWidth, chartHeight]);
92
+ const textRef = useRef(null);
93
+ const [textBBox, setTextBBox] = useState(null);
94
+ const isDimensionsReady = disableRepositioning || textRef.current !== null;
95
+ const backgroundRectDimensions = useMemo(() => {
96
+ if (!textBBox) {
97
+ return null;
98
+ }
99
+ const inset = getChartInset(insetInput);
100
+ return {
101
+ x: textBBox.x - inset.left,
102
+ y: textBBox.y - inset.top,
103
+ width: textBBox.width + inset.left + inset.right,
104
+ height: textBBox.height + inset.top + inset.bottom
105
+ };
106
+ }, [textBBox, insetInput]);
107
+ const overflowAmount = useMemo(() => {
108
+ if (disableRepositioning) {
109
+ return {
110
+ x: 0,
111
+ y: 0
112
+ };
113
+ }
114
+ const parentBounds = bounds !== null && bounds !== void 0 ? bounds : fullChartBounds;
115
+ if (!textBBox || !parentBounds || parentBounds.width <= 0 || parentBounds.height <= 0) {
116
+ return {
117
+ x: 0,
118
+ y: 0
119
+ };
120
+ }
121
+ let x = 0;
122
+ let y = 0;
123
+
124
+ // X-axis overflow
125
+ if (textBBox.x < parentBounds.x) {
126
+ x = parentBounds.x - textBBox.x; // positive = shift right
127
+ } else if (textBBox.x + textBBox.width > parentBounds.x + parentBounds.width) {
128
+ x = parentBounds.x + parentBounds.width - (textBBox.x + textBBox.width); // negative = shift left
129
+ }
130
+
131
+ // Y-axis overflow
132
+ if (textBBox.y < parentBounds.y) {
133
+ y = parentBounds.y - textBBox.y; // positive = shift down
134
+ } else if (textBBox.y + textBBox.height > parentBounds.y + parentBounds.height) {
135
+ y = parentBounds.y + parentBounds.height - (textBBox.y + textBBox.height); // negative = shift up
136
+ }
137
+ return {
138
+ x,
139
+ y
140
+ };
141
+ }, [textBBox, fullChartBounds, bounds, disableRepositioning]);
142
+
143
+ // Compose the final reported rect including any overflow translation applied
144
+ const reportedRect = useMemo(() => {
145
+ if (!backgroundRectDimensions) return null;
146
+ return {
147
+ x: backgroundRectDimensions.x + overflowAmount.x,
148
+ y: backgroundRectDimensions.y + overflowAmount.y,
149
+ width: backgroundRectDimensions.width,
150
+ height: backgroundRectDimensions.height
151
+ };
152
+ }, [backgroundRectDimensions, overflowAmount.x, overflowAmount.y]);
153
+
154
+ // send latest calculated dimensions (adjusted for translation) to parent
155
+ useEffect(() => {
156
+ if (onDimensionsChange && reportedRect !== null) {
157
+ onDimensionsChange(reportedRect);
158
+ }
159
+ }, [reportedRect, onDimensionsChange]);
160
+ useEffect(() => {
161
+ if (textRef.current) {
162
+ const observer = new ResizeObserver(entries => {
163
+ for (const entry of entries) {
164
+ setTextBBox(entry.target.getBBox());
165
+ }
166
+ });
167
+ observer.observe(textRef.current);
168
+
169
+ // Cleanup function
170
+ return () => {
171
+ observer.disconnect();
172
+ };
173
+ }
174
+ }, []);
175
+ const textAnchor = useMemo(() => getTextAnchor(horizontalAlignment), [horizontalAlignment]);
176
+ const dominantBaseline = useMemo(() => getDominantBaseline(verticalAlignment), [verticalAlignment]);
177
+
178
+ // forces state update the bounding box when any properties that can affect the bounding box change
179
+ useEffect(() => {
180
+ if (textRef.current) {
181
+ setTextBBox(textRef.current.getBBox());
182
+ }
183
+ }, [textAnchor, dominantBaseline, dx, dy, x, y]);
184
+ const containerStyle = useMemo(() => _objectSpread(_objectSpread(_objectSpread({}, style), styles === null || styles === void 0 ? void 0 : styles.root), {}, {
185
+ transform: "translate(".concat(overflowAmount.x, "px, ").concat(overflowAmount.y, "px)")
186
+ }), [overflowAmount.x, overflowAmount.y, style, styles === null || styles === void 0 ? void 0 : styles.root]);
187
+ return /*#__PURE__*/_jsx(Box, {
188
+ "aria-hidden": "true",
189
+ as: "g",
190
+ className: cx(className, classNames === null || classNames === void 0 ? void 0 : classNames.root),
191
+ opacity: opacity,
192
+ style: containerStyle,
193
+ testID: testID,
194
+ children: /*#__PURE__*/_jsxs(motion.g, {
195
+ animate: {
196
+ opacity: isDimensionsReady ? 1 : 0
197
+ },
198
+ transition: animate ? {
199
+ duration: 0.2,
200
+ ease: 'easeOut'
201
+ } : undefined,
202
+ children: [/*#__PURE__*/_jsx(Box, {
203
+ as: "rect",
204
+ className: classNames === null || classNames === void 0 ? void 0 : classNames.backgroundRect,
205
+ fill: background,
206
+ filter: elevation && elevation > 0 ? "drop-shadow(var(--shadow-elevation".concat(elevation, "))") : undefined,
207
+ height: backgroundRectDimensions === null || backgroundRectDimensions === void 0 ? void 0 : backgroundRectDimensions.height,
208
+ rx: borderRadius,
209
+ ry: borderRadius,
210
+ style: styles === null || styles === void 0 ? void 0 : styles.backgroundRect,
211
+ width: backgroundRectDimensions === null || backgroundRectDimensions === void 0 ? void 0 : backgroundRectDimensions.width,
212
+ x: backgroundRectDimensions === null || backgroundRectDimensions === void 0 ? void 0 : backgroundRectDimensions.x,
213
+ y: backgroundRectDimensions === null || backgroundRectDimensions === void 0 ? void 0 : backgroundRectDimensions.y
214
+ }), /*#__PURE__*/_jsx(Text, {
215
+ ref: textRef,
216
+ as: "text",
217
+ className: classNames === null || classNames === void 0 ? void 0 : classNames.text,
218
+ dominantBaseline: dominantBaseline,
219
+ dx: dx,
220
+ dy: dy,
221
+ fill: color,
222
+ font: font,
223
+ fontFamily: fontFamily,
224
+ fontSize: fontSize,
225
+ fontWeight: fontWeight,
226
+ style: styles === null || styles === void 0 ? void 0 : styles.text,
227
+ textAnchor: textAnchor,
228
+ x: x,
229
+ y: y,
230
+ children: /*#__PURE__*/_jsx("tspan", {
231
+ children: children
232
+ })
233
+ })]
234
+ })
235
+ });
236
+ });