@coinbase/cds-web-visualization 3.4.0-beta.2 → 3.4.0-beta.20

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 (198) hide show
  1. package/CHANGELOG.md +115 -0
  2. package/dts/chart/CartesianChart.d.ts +56 -3
  3. package/dts/chart/CartesianChart.d.ts.map +1 -1
  4. package/dts/chart/ChartProvider.d.ts +3 -0
  5. package/dts/chart/ChartProvider.d.ts.map +1 -1
  6. package/dts/chart/Path.d.ts +64 -7
  7. package/dts/chart/Path.d.ts.map +1 -1
  8. package/dts/chart/PeriodSelector.d.ts +5 -15
  9. package/dts/chart/PeriodSelector.d.ts.map +1 -1
  10. package/dts/chart/area/Area.d.ts +50 -25
  11. package/dts/chart/area/Area.d.ts.map +1 -1
  12. package/dts/chart/area/AreaChart.d.ts +46 -6
  13. package/dts/chart/area/AreaChart.d.ts.map +1 -1
  14. package/dts/chart/area/DottedArea.d.ts +21 -44
  15. package/dts/chart/area/DottedArea.d.ts.map +1 -1
  16. package/dts/chart/area/GradientArea.d.ts +21 -12
  17. package/dts/chart/area/GradientArea.d.ts.map +1 -1
  18. package/dts/chart/area/SolidArea.d.ts +16 -1
  19. package/dts/chart/area/SolidArea.d.ts.map +1 -1
  20. package/dts/chart/axis/Axis.d.ts +109 -63
  21. package/dts/chart/axis/Axis.d.ts.map +1 -1
  22. package/dts/chart/axis/DefaultAxisTickLabel.d.ts +8 -0
  23. package/dts/chart/axis/DefaultAxisTickLabel.d.ts.map +1 -0
  24. package/dts/chart/axis/XAxis.d.ts +1 -1
  25. package/dts/chart/axis/XAxis.d.ts.map +1 -1
  26. package/dts/chart/axis/YAxis.d.ts +2 -2
  27. package/dts/chart/axis/YAxis.d.ts.map +1 -1
  28. package/dts/chart/axis/index.d.ts +1 -0
  29. package/dts/chart/axis/index.d.ts.map +1 -1
  30. package/dts/chart/bar/Bar.d.ts +50 -12
  31. package/dts/chart/bar/Bar.d.ts.map +1 -1
  32. package/dts/chart/bar/BarChart.d.ts +20 -8
  33. package/dts/chart/bar/BarChart.d.ts.map +1 -1
  34. package/dts/chart/bar/BarPlot.d.ts +3 -1
  35. package/dts/chart/bar/BarPlot.d.ts.map +1 -1
  36. package/dts/chart/bar/BarStack.d.ts +41 -46
  37. package/dts/chart/bar/BarStack.d.ts.map +1 -1
  38. package/dts/chart/bar/BarStackGroup.d.ts +2 -0
  39. package/dts/chart/bar/BarStackGroup.d.ts.map +1 -1
  40. package/dts/chart/bar/DefaultBar.d.ts.map +1 -1
  41. package/dts/chart/bar/DefaultBarStack.d.ts.map +1 -1
  42. package/dts/chart/gradient/Gradient.d.ts +35 -0
  43. package/dts/chart/gradient/Gradient.d.ts.map +1 -0
  44. package/dts/chart/gradient/index.d.ts +2 -0
  45. package/dts/chart/gradient/index.d.ts.map +1 -0
  46. package/dts/chart/index.d.ts +3 -1
  47. package/dts/chart/index.d.ts.map +1 -1
  48. package/dts/chart/legend/DefaultLegendEntry.d.ts +21 -0
  49. package/dts/chart/legend/DefaultLegendEntry.d.ts.map +1 -0
  50. package/dts/chart/legend/DefaultLegendShape.d.ts +7 -0
  51. package/dts/chart/legend/DefaultLegendShape.d.ts.map +1 -0
  52. package/dts/chart/legend/Legend.d.ts +169 -0
  53. package/dts/chart/legend/Legend.d.ts.map +1 -0
  54. package/dts/chart/legend/index.d.ts +4 -0
  55. package/dts/chart/legend/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 +15 -3
  59. package/dts/chart/line/DottedLine.d.ts.map +1 -1
  60. package/dts/chart/line/Line.d.ts +84 -28
  61. package/dts/chart/line/Line.d.ts.map +1 -1
  62. package/dts/chart/line/LineChart.d.ts +28 -8
  63. package/dts/chart/line/LineChart.d.ts.map +1 -1
  64. package/dts/chart/line/ReferenceLine.d.ts +91 -44
  65. package/dts/chart/line/ReferenceLine.d.ts.map +1 -1
  66. package/dts/chart/line/SolidLine.d.ts +14 -3
  67. package/dts/chart/line/SolidLine.d.ts.map +1 -1
  68. package/dts/chart/line/index.d.ts +1 -1
  69. package/dts/chart/line/index.d.ts.map +1 -1
  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 +217 -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 +41 -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 +10 -0
  81. package/dts/chart/scrubber/DefaultScrubberLabel.d.ts.map +1 -0
  82. package/dts/chart/scrubber/Scrubber.d.ts +287 -70
  83. package/dts/chart/scrubber/Scrubber.d.ts.map +1 -1
  84. package/dts/chart/scrubber/ScrubberBeaconGroup.d.ts +80 -0
  85. package/dts/chart/scrubber/ScrubberBeaconGroup.d.ts.map +1 -0
  86. package/dts/chart/scrubber/ScrubberBeaconLabelGroup.d.ts +47 -0
  87. package/dts/chart/scrubber/ScrubberBeaconLabelGroup.d.ts.map +1 -0
  88. package/dts/chart/scrubber/index.d.ts +3 -0
  89. package/dts/chart/scrubber/index.d.ts.map +1 -1
  90. package/dts/chart/text/ChartText.d.ts +46 -43
  91. package/dts/chart/text/ChartText.d.ts.map +1 -1
  92. package/dts/chart/text/{SmartChartTextGroup.d.ts → ChartTextGroup.d.ts} +9 -3
  93. package/dts/chart/text/ChartTextGroup.d.ts.map +1 -0
  94. package/dts/chart/text/index.d.ts +1 -1
  95. package/dts/chart/text/index.d.ts.map +1 -1
  96. package/dts/chart/utils/axis.d.ts +25 -1
  97. package/dts/chart/utils/axis.d.ts.map +1 -1
  98. package/dts/chart/utils/bar.d.ts +34 -0
  99. package/dts/chart/utils/bar.d.ts.map +1 -1
  100. package/dts/chart/utils/chart.d.ts +45 -7
  101. package/dts/chart/utils/chart.d.ts.map +1 -1
  102. package/dts/chart/utils/context.d.ts +6 -0
  103. package/dts/chart/utils/context.d.ts.map +1 -1
  104. package/dts/chart/utils/gradient.d.ts +104 -0
  105. package/dts/chart/utils/gradient.d.ts.map +1 -0
  106. package/dts/chart/utils/index.d.ts +4 -0
  107. package/dts/chart/utils/index.d.ts.map +1 -1
  108. package/dts/chart/utils/interpolate.d.ts +112 -0
  109. package/dts/chart/utils/interpolate.d.ts.map +1 -0
  110. package/dts/chart/utils/path.d.ts +30 -1
  111. package/dts/chart/utils/path.d.ts.map +1 -1
  112. package/dts/chart/utils/point.d.ts +40 -7
  113. package/dts/chart/utils/point.d.ts.map +1 -1
  114. package/dts/chart/utils/scale.d.ts +11 -0
  115. package/dts/chart/utils/scale.d.ts.map +1 -1
  116. package/dts/chart/utils/scrubber.d.ts +40 -0
  117. package/dts/chart/utils/scrubber.d.ts.map +1 -0
  118. package/dts/chart/utils/transition.d.ts +101 -0
  119. package/dts/chart/utils/transition.d.ts.map +1 -0
  120. package/dts/sparkline/sparkline-interactive/SparklineInteractiveMarkerDates.d.ts.map +1 -1
  121. package/esm/chart/CartesianChart.js +170 -83
  122. package/esm/chart/ChartProvider.js +2 -2
  123. package/esm/chart/Path.js +59 -54
  124. package/esm/chart/PeriodSelector.js +36 -32
  125. package/esm/chart/area/Area.js +26 -34
  126. package/esm/chart/area/AreaChart.js +29 -15
  127. package/esm/chart/area/DottedArea.js +39 -89
  128. package/esm/chart/area/GradientArea.js +37 -80
  129. package/esm/chart/area/SolidArea.js +32 -11
  130. package/esm/chart/axis/Axis.js +4 -39
  131. package/esm/chart/axis/DefaultAxisTickLabel.js +15 -0
  132. package/esm/chart/axis/XAxis.js +184 -63
  133. package/esm/chart/axis/YAxis.js +190 -57
  134. package/esm/chart/axis/index.js +1 -0
  135. package/esm/chart/bar/Bar.js +7 -1
  136. package/esm/chart/bar/BarChart.js +17 -32
  137. package/esm/chart/bar/BarPlot.js +5 -2
  138. package/esm/chart/bar/BarStack.js +74 -22
  139. package/esm/chart/bar/BarStackGroup.js +8 -18
  140. package/esm/chart/bar/DefaultBar.js +23 -28
  141. package/esm/chart/bar/DefaultBarStack.js +24 -20
  142. package/esm/chart/gradient/Gradient.js +104 -0
  143. package/esm/chart/gradient/index.js +1 -0
  144. package/esm/chart/index.js +3 -1
  145. package/esm/chart/legend/DefaultLegendEntry.css +1 -0
  146. package/esm/chart/legend/DefaultLegendEntry.js +50 -0
  147. package/esm/chart/legend/DefaultLegendShape.css +5 -0
  148. package/esm/chart/legend/DefaultLegendShape.js +47 -0
  149. package/esm/chart/legend/Legend.js +76 -0
  150. package/esm/chart/legend/index.js +3 -0
  151. package/esm/chart/line/DefaultReferenceLineLabel.js +81 -0
  152. package/esm/chart/line/DottedLine.js +41 -17
  153. package/esm/chart/line/Line.js +87 -75
  154. package/esm/chart/line/LineChart.js +24 -8
  155. package/esm/chart/line/ReferenceLine.js +41 -43
  156. package/esm/chart/line/SolidLine.js +39 -15
  157. package/esm/chart/line/index.js +1 -1
  158. package/esm/chart/{line/GradientLine.js → point/DefaultPointLabel.js} +31 -45
  159. package/esm/chart/point/Point.css +2 -0
  160. package/esm/chart/{Point.js → point/Point.js} +87 -62
  161. package/esm/chart/point/index.js +2 -0
  162. package/esm/chart/scrubber/DefaultScrubberBeacon.js +154 -0
  163. package/esm/chart/scrubber/DefaultScrubberBeaconLabel.js +57 -0
  164. package/esm/chart/scrubber/{ScrubberBeaconLabel.js → DefaultScrubberLabel.js} +15 -18
  165. package/esm/chart/scrubber/Scrubber.js +97 -392
  166. package/esm/chart/scrubber/ScrubberBeaconGroup.js +174 -0
  167. package/esm/chart/scrubber/ScrubberBeaconLabelGroup.js +201 -0
  168. package/esm/chart/scrubber/index.js +3 -1
  169. package/esm/chart/text/ChartText.js +15 -20
  170. package/esm/chart/text/{SmartChartTextGroup.js → ChartTextGroup.js} +4 -3
  171. package/esm/chart/text/index.js +1 -1
  172. package/esm/chart/utils/axis.js +47 -31
  173. package/esm/chart/utils/bar.js +48 -0
  174. package/esm/chart/utils/chart.js +42 -3
  175. package/esm/chart/utils/gradient.js +257 -0
  176. package/esm/chart/utils/index.js +4 -0
  177. package/esm/chart/utils/interpolate.js +644 -0
  178. package/esm/chart/utils/path.js +41 -9
  179. package/esm/chart/utils/point.js +99 -12
  180. package/esm/chart/utils/scale.js +13 -2
  181. package/esm/chart/utils/scrubber.js +137 -0
  182. package/esm/chart/utils/transition.js +133 -0
  183. package/esm/sparkline/__figma__/Sparkline.figma.js +1 -1
  184. package/esm/sparkline/sparkline-interactive/SparklineInteractiveMarkerDates.js +8 -4
  185. package/esm/sparkline/sparkline-interactive/__figma__/SparklineInteractive.figma.js +1 -1
  186. package/esm/sparkline/sparkline-interactive-header/__figma__/SparklineInteractiveHeader.figma.js +1 -1
  187. package/package.json +12 -11
  188. package/dts/chart/Point.d.ts +0 -153
  189. package/dts/chart/Point.d.ts.map +0 -1
  190. package/dts/chart/line/GradientLine.d.ts +0 -42
  191. package/dts/chart/line/GradientLine.d.ts.map +0 -1
  192. package/dts/chart/scrubber/ScrubberBeacon.d.ts +0 -93
  193. package/dts/chart/scrubber/ScrubberBeacon.d.ts.map +0 -1
  194. package/dts/chart/scrubber/ScrubberBeaconLabel.d.ts +0 -7
  195. package/dts/chart/scrubber/ScrubberBeaconLabel.d.ts.map +0 -1
  196. package/dts/chart/text/SmartChartTextGroup.d.ts.map +0 -1
  197. package/esm/chart/Point.css +0 -2
  198. package/esm/chart/scrubber/ScrubberBeacon.js +0 -195
@@ -1,3 +1,51 @@
1
+ const _excluded = ["staggerDelay"];
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 { defaultTransition } from './transition';
10
+
11
+ /**
12
+ * A bar-specific transition that extends Transition with stagger support.
13
+ * When `staggerDelay` is provided, bars will animate with increasing delays
14
+ * based on their horizontal position (leftmost starts first, rightmost last).
15
+ *
16
+ * @example
17
+ * // Bars stagger in from left to right over 0.25s, each animating for 0.75s
18
+ * { type: 'tween', duration: 0.75, staggerDelay: 0.25 }
19
+ */
20
+
21
+ /**
22
+ * Strips `staggerDelay` from a transition and computes a positional delay.
23
+ *
24
+ * @param transition - The transition config (may include staggerDelay)
25
+ * @param normalizedX - The bar's normalized x position (0 = left edge, 1 = right edge)
26
+ * @returns A standard Transition with computed delay
27
+ */
28
+ export const withStaggerDelayTransition = (transition, normalizedX) => {
29
+ var _baseTransition$delay;
30
+ const {
31
+ staggerDelay
32
+ } = transition,
33
+ baseTransition = _objectWithoutProperties(transition, _excluded);
34
+ if (!staggerDelay) return transition;
35
+ return _objectSpread(_objectSpread({}, baseTransition), {}, {
36
+ delay: ((_baseTransition$delay = baseTransition === null || baseTransition === void 0 ? void 0 : baseTransition.delay) !== null && _baseTransition$delay !== void 0 ? _baseTransition$delay : 0) + normalizedX * staggerDelay
37
+ });
38
+ };
39
+
40
+ /**
41
+ * Default bar enter transition. Uses the default spring with a stagger delay
42
+ * so bars spring into place from left to right.
43
+ * `{ type: 'spring', stiffness: 900, damping: 120, mass: 4, staggerDelay: 0.25 }`
44
+ */
45
+ export const defaultBarEnterTransition = _objectSpread(_objectSpread({}, defaultTransition), {}, {
46
+ staggerDelay: 0.25
47
+ });
48
+
1
49
  /**
2
50
  * Calculates the size adjustment needed for bars when accounting for gaps between them.
3
51
  * This function helps determine how much to reduce each bar's width to accommodate
@@ -1,5 +1,18 @@
1
1
  import { stack as d3Stack, stackOffsetDiverging, stackOrderNone } from 'd3-shape';
2
2
  export const defaultStackId = 'DEFAULT_STACK_ID';
3
+
4
+ /**
5
+ * Shape variants available for legend items.
6
+ */
7
+
8
+ /**
9
+ * Shape for legend items. Can be a preset variant or a custom ReactNode.
10
+ */
11
+
12
+ /**
13
+ * Position of the legend relative to the chart.
14
+ */
15
+
3
16
  /**
4
17
  * Type guard to check if bounds are complete with both min and max values.
5
18
  * @param bounds - The bounds to validate
@@ -19,13 +32,13 @@ export const getChartDomain = (series, min, max) => {
19
32
  return domain;
20
33
  }
21
34
  if (series.length > 0) {
22
- const maxDataLength = Math.max(...series.map(s => {
35
+ const dataLength = Math.max(...series.map(s => {
23
36
  var _s$data;
24
37
  return ((_s$data = s.data) === null || _s$data === void 0 ? void 0 : _s$data.length) || 0;
25
38
  }));
26
- if (maxDataLength > 0) {
39
+ if (dataLength > 0) {
27
40
  if (domain.min === undefined) domain.min = 0;
28
- if (domain.max === undefined) domain.max = maxDataLength - 1;
41
+ if (domain.max === undefined) domain.max = dataLength - 1;
29
42
  }
30
43
  }
31
44
  return domain;
@@ -111,6 +124,32 @@ export const getStackedSeriesData = series => {
111
124
  return stackedDataMap;
112
125
  };
113
126
 
127
+ /**
128
+ * Extracts line data values from series data that may contain tuples.
129
+ * For tuple data [[baseline, value]], extracts the last value.
130
+ * For numeric data [value], returns as-is.
131
+ *
132
+ * @param data - Array of numbers, tuples, or null values
133
+ * @returns Array of numbers or null values
134
+ */
135
+ export const getLineData = data => {
136
+ if (!data) return [];
137
+
138
+ // Check if this is tuple data by finding first non-null entry
139
+ const firstNonNull = data.find(d => d !== null);
140
+ if (Array.isArray(firstNonNull)) {
141
+ return data.map(d => {
142
+ var _d$at;
143
+ if (d === null) return null;
144
+ if (Array.isArray(d)) return (_d$at = d.at(-1)) !== null && _d$at !== void 0 ? _d$at : null;
145
+ return d;
146
+ });
147
+ }
148
+
149
+ // Already numeric data
150
+ return data;
151
+ };
152
+
114
153
  /**
115
154
  * Calculates the range of a chart from series data.
116
155
  * Range represents the range of y-values from the data.
@@ -0,0 +1,257 @@
1
+ import { isCategoricalScale } from './scale';
2
+
3
+ /**
4
+ * Defines a color transition point in the gradient
5
+ */
6
+
7
+ /**
8
+ * Defines a gradient.
9
+ */
10
+
11
+ /**
12
+ * Resolves gradient stops, handling both static arrays and function forms.
13
+ * When stops is a function, calls it with the domain bounds.
14
+ */
15
+ const getGradientStops = (stops, domain) => {
16
+ if (typeof stops === 'function') {
17
+ return stops(domain);
18
+ }
19
+ return stops;
20
+ };
21
+
22
+ /**
23
+ * Processes Gradient to gradient configuration for SVG linearGradient.
24
+ * Colors are smoothly interpolated between stops by the browser.
25
+ * Multiple stops at the same offset create hard color transitions.
26
+ */
27
+ const processGradientStops = (stops, scale) => {
28
+ if (stops.length === 0) {
29
+ console.warn('Gradient has no stops - falling back to default');
30
+ return;
31
+ }
32
+
33
+ // Check if stops are in ascending order
34
+ const isOutOfOrder = stops.some((stop, i) => {
35
+ return i > 0 && stop.offset < stops[i - 1].offset;
36
+ });
37
+ if (isOutOfOrder) {
38
+ console.warn("Gradient: stop offsets must be in ascending order");
39
+ return;
40
+ }
41
+ const [rangeMin, rangeMax] = scale.range();
42
+ const rangeSpan = Math.abs(rangeMax - rangeMin);
43
+
44
+ // Convert data value offsets to normalized positions (0-1) using scale
45
+ const normalizedStops = stops.map(stop => {
46
+ var _stop$opacity;
47
+ const stopPosition = scale(stop.offset);
48
+ const normalized = stopPosition === undefined ? 0 : Math.max(0, Math.min(1, Math.abs(stopPosition - rangeMin) / rangeSpan));
49
+ return {
50
+ offset: normalized,
51
+ // Now 0-1 normalized (not data space)
52
+ color: stop.color,
53
+ opacity: (_stop$opacity = stop.opacity) !== null && _stop$opacity !== void 0 ? _stop$opacity : 1
54
+ };
55
+ }).sort((a, b) => a.offset - b.offset);
56
+ return normalizedStops;
57
+ };
58
+
59
+ /**
60
+ * Evaluates the color at a specific data value based on the gradient stops, ignoring opacity.
61
+ * @param stops - The gradient stops configuration
62
+ * @param dataValue - The data value to evaluate (for band scales, this is the index)
63
+ * @param scale - The scale to use for value mapping (handles log scales correctly)
64
+ * @returns The color string at this data value, or undefined if invalid
65
+ */
66
+ export const evaluateGradientAtValue = (stops, dataValue, scale) => {
67
+ if (stops.length === 0) return;
68
+
69
+ // Use srgb color space to match our linearGradient which uses srgb color space
70
+ // https://www.w3.org/TR/SVG11/painting.html#ColorInterpolationProperty
71
+ const colorSpace = 'srgb';
72
+
73
+ // Use scale to map values to positions (handles log scales correctly)
74
+ // For numeric scales: scale(value) returns pixel position
75
+ // We normalize these positions to 0-1 based on the range
76
+ const scaleRange = scale.range();
77
+ const [rangeMin, rangeMax] = Array.isArray(scaleRange) ? scaleRange : [scaleRange, scaleRange]; // fallback for band scales
78
+
79
+ const rangeSpan = Math.abs(rangeMax - rangeMin);
80
+ if (rangeSpan === 0) return stops[0].color;
81
+
82
+ // Map dataValue through scale to get position
83
+ const dataPosition = scale(dataValue);
84
+ if (dataPosition === undefined) return stops[0].color;
85
+
86
+ // Normalize to 0-1 based on range
87
+ const normalizedValue = Math.max(0, Math.min(1, Math.abs(dataPosition - rangeMin) / rangeSpan));
88
+
89
+ // stops already have normalized offsets (0-1), use them directly
90
+ const positions = stops.map(stop => stop.offset);
91
+
92
+ // Find which segment we're in
93
+ if (normalizedValue < positions[0]) {
94
+ return stops[0].color;
95
+ }
96
+ if (normalizedValue >= positions[positions.length - 1]) {
97
+ return stops[stops.length - 1].color;
98
+ }
99
+
100
+ // Check if normalizedValue matches any stop offset exactly (for hard transitions)
101
+ for (let i = 0; i < stops.length; i++) {
102
+ if (Math.abs(normalizedValue - stops[i].offset) < 1e-10) {
103
+ // Found exact match - check if there are multiple stops at this offset (hard transition)
104
+ // Use the LAST color at this offset for hard transitions
105
+ let lastIndexAtOffset = i;
106
+ while (lastIndexAtOffset + 1 < stops.length && Math.abs(stops[lastIndexAtOffset + 1].offset - stops[i].offset) < 1e-10) {
107
+ lastIndexAtOffset++;
108
+ }
109
+ return stops[lastIndexAtOffset].color;
110
+ }
111
+ }
112
+
113
+ // Find the two colors to mix based on normalized positions
114
+ for (let i = 0; i < positions.length - 1; i++) {
115
+ const start = positions[i];
116
+ const end = positions[i + 1];
117
+ if (normalizedValue >= start && normalizedValue <= end) {
118
+ const segmentProgress = (normalizedValue - start) / (end - start);
119
+ return "color-mix(in ".concat(colorSpace, ", ").concat(stops[i + 1].color, " ").concat(segmentProgress * 100, "%, ").concat(stops[i].color, ")");
120
+ }
121
+ }
122
+
123
+ // If we didn't reach any to be mixed, return the last color
124
+ return stops[stops.length - 1].color;
125
+ };
126
+
127
+ /**
128
+ * Creates a gradient configuration for SVG components.
129
+ * Processes a GradientDefinition into a renderable GradientConfig.
130
+ * Supports both numeric scales (linear, log) and categorical scales (band).
131
+ *
132
+ * @param gradient - GradientDefinition configuration (required)
133
+ * @param xScale - X-axis scale (required)
134
+ * @param yScale - Y-axis scale (required)
135
+ * @returns GradientConfig or null if gradient processing fails
136
+ *
137
+ * @example
138
+ * const gradientConfig = useMemo(() => {
139
+ * if (!gradient || !xScale || !yScale) return;
140
+ * return getGradientConfig(gradient, xScale, yScale);
141
+ * }, [gradient, xScale, yScale]);
142
+ *
143
+ * if (gradientConfig) {
144
+ * return (
145
+ * <defs>
146
+ * <Gradient
147
+ * config={gradientConfig}
148
+ * direction={gradient.axis === 'x' ? 'horizontal' : 'vertical'}
149
+ * id={gradientId}
150
+ * />
151
+ * </defs>
152
+ * );
153
+ * }
154
+ */
155
+ export const getGradientConfig = (gradient, xScale, yScale) => {
156
+ if (!gradient) return;
157
+
158
+ // Get the scale based on axis
159
+ const scale = gradient.axis === 'x' ? xScale : yScale;
160
+ if (!scale) return;
161
+
162
+ // Extract domain from scale
163
+ const scaleDomain = scale.domain();
164
+ let domain;
165
+ if (isCategoricalScale(scale)) {
166
+ const domainArray = scaleDomain;
167
+ domain = {
168
+ min: domainArray[0],
169
+ max: domainArray[domainArray.length - 1]
170
+ };
171
+ } else {
172
+ const [min, max] = scaleDomain;
173
+ domain = {
174
+ min,
175
+ max
176
+ };
177
+ }
178
+ const resolvedStops = getGradientStops(gradient.stops, domain);
179
+ return processGradientStops(resolvedStops, scale);
180
+ };
181
+
182
+ /**
183
+ * Determines the baseline value for the gradient area by finding the value
184
+ * within the axis bounds that is closest to the target baseline.
185
+ *
186
+ * @param axisBounds - The min and max bounds of the axis
187
+ * @param baseline - The target baseline value (defaults to 0)
188
+ * @returns The value within bounds closest to the baseline
189
+ */
190
+ export const getBaseline = function (axisBounds) {
191
+ let baseline = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
192
+ const {
193
+ min,
194
+ max
195
+ } = axisBounds;
196
+
197
+ // Normalize to ensure lowerBound <= upperBound
198
+ const lowerBound = Math.min(min, max);
199
+ const upperBound = Math.max(min, max);
200
+
201
+ // If baseline is within the range, use it
202
+ if (lowerBound <= baseline && baseline <= upperBound) return baseline;
203
+
204
+ // Otherwise, return the bound closest to baseline
205
+ return Math.abs(lowerBound - baseline) < Math.abs(upperBound - baseline) ? lowerBound : upperBound;
206
+ };
207
+
208
+ /**
209
+ * Generates a gradient definition for the area chart based on the axis bounds
210
+ * and styling parameters. Ensures gradient stops are in ascending order.
211
+ *
212
+ * @param axisBounds - The min and max bounds of the axis
213
+ * @param baselineValue - The baseline value for the gradient
214
+ * @param fill - The color to use for the gradient
215
+ * @param peakOpacity - Opacity at the peak of the gradient
216
+ * @param baselineOpacity - Opacity at the baseline
217
+ * @returns A gradient definition with y-axis stops in ascending order
218
+ */
219
+ export const createGradient = (axisBounds, baselineValue, fill, peakOpacity, baselineOpacity) => {
220
+ const {
221
+ min,
222
+ max
223
+ } = axisBounds;
224
+ const lowerBound = Math.min(min, max);
225
+ const upperBound = Math.max(min, max);
226
+ if (lowerBound < baselineValue && baselineValue < upperBound) {
227
+ return {
228
+ axis: 'y',
229
+ stops: [{
230
+ offset: lowerBound,
231
+ color: fill,
232
+ opacity: peakOpacity
233
+ }, {
234
+ offset: baselineValue,
235
+ color: fill,
236
+ opacity: baselineOpacity
237
+ }, {
238
+ offset: upperBound,
239
+ color: fill,
240
+ opacity: peakOpacity
241
+ }]
242
+ };
243
+ }
244
+ const peakValue = Math.abs(min - baselineValue) > Math.abs(max - baselineValue) ? min : max;
245
+ return {
246
+ axis: 'y',
247
+ stops: [{
248
+ offset: peakValue,
249
+ color: fill,
250
+ opacity: peakOpacity
251
+ }, {
252
+ offset: baselineValue,
253
+ color: fill,
254
+ opacity: baselineOpacity
255
+ }].sort((a, b) => a.offset - b.offset)
256
+ };
257
+ };
@@ -3,7 +3,11 @@ export * from './axis';
3
3
  export * from './bar';
4
4
  export * from './chart';
5
5
  export * from './context';
6
+ export * from './gradient';
7
+ export * from './interpolate';
6
8
  export * from './path';
7
9
  export * from './point';
8
10
  export * from './scale';
11
+ export * from './scrubber';
12
+ export * from './transition';
9
13
  // codegen:end