@coinbase/cds-mobile-visualization 3.6.2 → 3.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dts/chart/CartesianChart.d.ts +4 -8
  3. package/dts/chart/CartesianChart.d.ts.map +1 -1
  4. package/dts/chart/PeriodSelector.d.ts.map +1 -1
  5. package/dts/chart/area/Area.d.ts +3 -0
  6. package/dts/chart/area/Area.d.ts.map +1 -1
  7. package/dts/chart/area/AreaChart.d.ts.map +1 -1
  8. package/dts/chart/area/DottedArea.d.ts.map +1 -1
  9. package/dts/chart/area/GradientArea.d.ts.map +1 -1
  10. package/dts/chart/area/SolidArea.d.ts.map +1 -1
  11. package/dts/chart/bar/BarChart.d.ts.map +1 -1
  12. package/dts/chart/bar/BarStack.d.ts.map +1 -1
  13. package/dts/chart/gradient/Gradient.d.ts +14 -3
  14. package/dts/chart/gradient/Gradient.d.ts.map +1 -1
  15. package/dts/chart/line/DottedLine.d.ts.map +1 -1
  16. package/dts/chart/line/Line.d.ts +3 -0
  17. package/dts/chart/line/Line.d.ts.map +1 -1
  18. package/dts/chart/line/LineChart.d.ts.map +1 -1
  19. package/dts/chart/line/SolidLine.d.ts.map +1 -1
  20. package/dts/chart/utils/axis.d.ts +18 -8
  21. package/dts/chart/utils/axis.d.ts.map +1 -1
  22. package/dts/chart/utils/bar.d.ts +17 -7
  23. package/dts/chart/utils/bar.d.ts.map +1 -1
  24. package/dts/chart/utils/chart.d.ts +9 -0
  25. package/dts/chart/utils/chart.d.ts.map +1 -1
  26. package/dts/chart/utils/context.d.ts +3 -3
  27. package/dts/chart/utils/context.d.ts.map +1 -1
  28. package/dts/chart/utils/gradient.d.ts +14 -4
  29. package/dts/chart/utils/gradient.d.ts.map +1 -1
  30. package/esm/chart/CartesianChart.js +6 -4
  31. package/esm/chart/PeriodSelector.js +3 -4
  32. package/esm/chart/__stories__/ChartTransitions.stories.js +68 -0
  33. package/esm/chart/area/Area.js +0 -2
  34. package/esm/chart/area/AreaChart.js +15 -19
  35. package/esm/chart/area/DottedArea.js +6 -4
  36. package/esm/chart/area/GradientArea.js +6 -4
  37. package/esm/chart/area/SolidArea.js +3 -0
  38. package/esm/chart/area/__stories__/AreaChart.stories.js +189 -3
  39. package/esm/chart/bar/BarChart.js +14 -22
  40. package/esm/chart/bar/BarStack.js +15 -10
  41. package/esm/chart/bar/__stories__/BarChart.stories.js +84 -2
  42. package/esm/chart/gradient/Gradient.js +119 -26
  43. package/esm/chart/line/DottedLine.js +3 -0
  44. package/esm/chart/line/Line.js +1 -3
  45. package/esm/chart/line/LineChart.js +8 -4
  46. package/esm/chart/line/SolidLine.js +3 -0
  47. package/esm/chart/utils/axis.js +32 -4
  48. package/esm/chart/utils/bar.js +129 -76
  49. package/esm/chart/utils/chart.js +53 -21
  50. package/esm/chart/utils/gradient.js +15 -5
  51. package/package.json +5 -5
@@ -31,6 +31,7 @@ const ThinSolidLine = /*#__PURE__*/memo(props => /*#__PURE__*/_jsx(SolidLine, _e
31
31
  strokeWidth: 1
32
32
  })));
33
33
  const defaultChartHeight = 250;
34
+ const baselineThresholdData = [40, 28, 21, 5, 48, 5, 28, 2, 29, 48, 18, 30, 29, 8].map(value => value + 50);
34
35
  const PositiveAndNegativeCashFlow = () => {
35
36
  const theme = useTheme();
36
37
  const categories = Array.from({
@@ -665,7 +666,7 @@ const BandGridPositionExample = _ref6 => {
665
666
 
666
667
  // --- Composed Examples ---
667
668
 
668
- const candlestickStockData = btcCandles.slice(0, 90).reverse();
669
+ const candlestickStockData = [...btcCandles].reverse().slice(0, 90);
669
670
  const CandlesticksHeader = /*#__PURE__*/memo(_ref7 => {
670
671
  let {
671
672
  currentIndex
@@ -1004,7 +1005,7 @@ const SunlightChart = () => {
1004
1005
  });
1005
1006
  };
1006
1007
  const PriceRange = () => {
1007
- const candles = btcCandles.slice(0, 180).reverse();
1008
+ const candles = [...btcCandles].reverse().slice(0, 180);
1008
1009
  const data = useMemo(() => candles.map(candle => [parseFloat(candle.low), parseFloat(candle.high)]), [candles]);
1009
1010
  const min = useMemo(() => Math.min(...data.map(_ref13 => {
1010
1011
  let [low] = _ref13;
@@ -1064,6 +1065,81 @@ const HorizontalBarChart = () => {
1064
1065
  }
1065
1066
  });
1066
1067
  };
1068
+ const AxisBaselineExample = () => {
1069
+ return /*#__PURE__*/_jsx(BarChart, {
1070
+ showXAxis: true,
1071
+ showYAxis: true,
1072
+ accessibilityLabel: "Bar chart with custom axis baseline at 100.",
1073
+ height: defaultChartHeight,
1074
+ series: [{
1075
+ id: 'net-flow',
1076
+ data: [112, 97, 121, 103, 129, 118, 94]
1077
+ }],
1078
+ xAxis: {
1079
+ data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
1080
+ },
1081
+ yAxis: {
1082
+ baseline: 100,
1083
+ domain: {
1084
+ min: 80,
1085
+ max: 140
1086
+ },
1087
+ showGrid: true
1088
+ }
1089
+ });
1090
+ };
1091
+ const AxisBaselineThresholdExample = () => {
1092
+ const theme = useTheme();
1093
+ return /*#__PURE__*/_jsxs(VStack, {
1094
+ gap: 2,
1095
+ children: [/*#__PURE__*/_jsx(BarChart, {
1096
+ showYAxis: true,
1097
+ accessibilityLabel: "Bar chart with threshold baseline at 30.",
1098
+ height: 220,
1099
+ inset: 0,
1100
+ series: [{
1101
+ id: 'axis-baseline-threshold-vertical',
1102
+ data: baselineThresholdData,
1103
+ gradient: {
1104
+ stops: [{
1105
+ offset: 30,
1106
+ color: theme.color.fgNegative
1107
+ }, {
1108
+ offset: 30,
1109
+ color: theme.color.fgPositive
1110
+ }]
1111
+ }
1112
+ }],
1113
+ yAxis: {
1114
+ showGrid: true,
1115
+ baseline: 30
1116
+ }
1117
+ }), /*#__PURE__*/_jsx(BarChart, {
1118
+ showXAxis: true,
1119
+ accessibilityLabel: "Horizontal bar chart with threshold baseline at 30.",
1120
+ height: 220,
1121
+ inset: 0,
1122
+ layout: "horizontal",
1123
+ series: [{
1124
+ id: 'axis-baseline-threshold-horizontal',
1125
+ data: baselineThresholdData,
1126
+ gradient: {
1127
+ stops: [{
1128
+ offset: 30,
1129
+ color: theme.color.fgNegative
1130
+ }, {
1131
+ offset: 30,
1132
+ color: theme.color.fgPositive
1133
+ }]
1134
+ }
1135
+ }],
1136
+ xAxis: {
1137
+ showGrid: true,
1138
+ baseline: 30
1139
+ }
1140
+ })]
1141
+ });
1142
+ };
1067
1143
  function BuyVsSellExample() {
1068
1144
  function BuyVsSellLegend(_ref15) {
1069
1145
  let {
@@ -1224,6 +1300,12 @@ function ExampleNavigator() {
1224
1300
  }, {
1225
1301
  title: 'Negative Values with Top Axis',
1226
1302
  component: /*#__PURE__*/_jsx(NegativeValuesWithTopAxis, {})
1303
+ }, {
1304
+ title: 'Axis Baseline',
1305
+ component: /*#__PURE__*/_jsx(AxisBaselineExample, {})
1306
+ }, {
1307
+ title: 'Axis Baseline Threshold',
1308
+ component: /*#__PURE__*/_jsx(AxisBaselineThresholdExample, {})
1227
1309
  }, {
1228
1310
  title: 'Positive and Negative Cash Flow',
1229
1311
  component: /*#__PURE__*/_jsx(PositiveAndNegativeCashFlow, {})
@@ -1,7 +1,9 @@
1
- import { memo, useMemo } from 'react';
2
- import { LinearGradient, vec } from '@shopify/react-native-skia';
1
+ import { memo, useEffect, useMemo, useRef } from 'react';
2
+ import { useDerivedValue, useSharedValue } from 'react-native-reanimated';
3
+ import { LinearGradient } from '@shopify/react-native-skia';
3
4
  import { useCartesianChartContext } from '../ChartProvider';
4
- import { getColorWithOpacity, getGradientConfig } from '../utils/gradient';
5
+ import { buildTransition, defaultTransition, instantTransition } from '../utils';
6
+ import { getColorWithOpacity, getGradientAxis, getGradientConfig } from '../utils/gradient';
5
7
  import { jsx as _jsx } from "react/jsx-runtime";
6
8
  /**
7
9
  * Renders a Skia LinearGradient element based on a GradientDefinition.
@@ -13,38 +15,129 @@ import { jsx as _jsx } from "react/jsx-runtime";
13
15
  * </Path>
14
16
  */
15
17
  export const Gradient = /*#__PURE__*/memo(_ref => {
16
- var _gradient$axis;
18
+ var _scale$range;
17
19
  let {
18
20
  gradient,
19
21
  xAxisId,
20
- yAxisId
22
+ yAxisId,
23
+ animate: animateProp,
24
+ transition: transitionProp
21
25
  } = _ref;
22
- const context = useCartesianChartContext();
23
- const xScale = context.getXScale(xAxisId);
24
- const yScale = context.getYScale(yAxisId);
25
- const axis = (_gradient$axis = gradient.axis) != null ? _gradient$axis : 'y';
26
- const scale = axis === 'x' ? xScale : yScale;
26
+ const {
27
+ animate: animateContext,
28
+ getXScale,
29
+ getYScale,
30
+ drawingArea,
31
+ layout
32
+ } = useCartesianChartContext();
33
+ const animate = animateProp != null ? animateProp : animateContext;
34
+ const transition = useMemo(() => {
35
+ if (!animate) return instantTransition;
36
+ return transitionProp != null ? transitionProp : defaultTransition;
37
+ }, [transitionProp, animate]);
38
+ const xScale = getXScale(xAxisId);
39
+ const yScale = getYScale(yAxisId);
27
40
 
28
41
  // Process gradient definition into stops
29
42
  const stops = useMemo(() => {
30
43
  if (!xScale || !yScale) return;
31
- return getGradientConfig(gradient, xScale, yScale);
32
- }, [gradient, xScale, yScale]);
33
- if (!stops || !scale) return;
34
- const range = scale.range();
35
-
36
- // Determine gradient direction based on axis
37
- // For y-axis, we need to flip the gradient direction because y-scales are inverted
38
- // (higher data values have smaller pixel values, appearing at the top)
39
- const start = axis === 'x' ? vec(range[0], 0) : vec(0, range[0]);
40
- const end = axis === 'x' ? vec(range[1], 0) : vec(0, range[1]);
44
+ return getGradientConfig(gradient, xScale, yScale, layout);
45
+ }, [gradient, xScale, yScale, layout]);
46
+ const axis = getGradientAxis(gradient, layout);
47
+ const scale = axis === 'x' ? xScale : yScale;
48
+ const shouldRender = !!stops && !!scale;
49
+ const range = (_scale$range = scale == null ? void 0 : scale.range()) != null ? _scale$range : [0, 0];
50
+ const [rangeStart = 0, rangeEnd = 0] = range;
51
+ const targetStart = axis === 'x' ? {
52
+ x: rangeStart,
53
+ y: drawingArea.y
54
+ } : {
55
+ x: drawingArea.x,
56
+ y: rangeStart
57
+ };
58
+ const targetEnd = axis === 'x' ? {
59
+ x: rangeEnd,
60
+ y: drawingArea.y
61
+ } : {
62
+ x: drawingArea.x,
63
+ y: rangeEnd
64
+ };
41
65
 
42
- // Extract colors and positions for LinearGradient
43
- const colors = stops.map(s => {
44
- var _s$opacity;
45
- return getColorWithOpacity(s.color, (_s$opacity = s.opacity) != null ? _s$opacity : 1);
46
- });
47
- const positions = stops.map(s => s.offset);
66
+ // Extract colors and positions for LinearGradient.
67
+ const colors = useMemo(() => (stops != null ? stops : []).map(stop => {
68
+ var _stop$opacity;
69
+ return getColorWithOpacity(stop.color, (_stop$opacity = stop.opacity) != null ? _stop$opacity : 1);
70
+ }), [stops]);
71
+ const targetPositions = useMemo(() => (stops != null ? stops : []).map(stop => stop.offset), [stops]);
72
+ const startX = useSharedValue(targetStart.x);
73
+ const startY = useSharedValue(targetStart.y);
74
+ const endX = useSharedValue(targetEnd.x);
75
+ const endY = useSharedValue(targetEnd.y);
76
+ const fromPositions = useSharedValue(targetPositions);
77
+ const toPositions = useSharedValue(targetPositions);
78
+ const positionsProgress = useSharedValue(1);
79
+ const hasRendered = useRef(false);
80
+ useEffect(() => {
81
+ if (!shouldRender) {
82
+ hasRendered.current = false;
83
+ return;
84
+ }
85
+ if (!hasRendered.current) {
86
+ hasRendered.current = true;
87
+ startX.value = targetStart.x;
88
+ startY.value = targetStart.y;
89
+ endX.value = targetEnd.x;
90
+ endY.value = targetEnd.y;
91
+ fromPositions.value = [...targetPositions];
92
+ toPositions.value = [...targetPositions];
93
+ positionsProgress.value = 1;
94
+ return;
95
+ }
96
+ startX.value = buildTransition(targetStart.x, transition);
97
+ startY.value = buildTransition(targetStart.y, transition);
98
+ endX.value = buildTransition(targetEnd.x, transition);
99
+ endY.value = buildTransition(targetEnd.y, transition);
100
+ const canAnimatePositions = toPositions.value.length === targetPositions.length;
101
+ if (canAnimatePositions) {
102
+ fromPositions.value = [...toPositions.value];
103
+ toPositions.value = [...targetPositions];
104
+ positionsProgress.value = 0;
105
+ positionsProgress.value = buildTransition(1, transition);
106
+ } else {
107
+ fromPositions.value = [...targetPositions];
108
+ toPositions.value = [...targetPositions];
109
+ positionsProgress.value = 1;
110
+ }
111
+ }, [transition, targetStart.x, targetStart.y, targetEnd.x, targetEnd.y, targetPositions, startX, startY, endX, endY, fromPositions, toPositions, positionsProgress, shouldRender]);
112
+ const start = useDerivedValue(() => {
113
+ return {
114
+ x: startX.value,
115
+ y: startY.value
116
+ };
117
+ }, [startX, startY]);
118
+ const end = useDerivedValue(() => {
119
+ return {
120
+ x: endX.value,
121
+ y: endY.value
122
+ };
123
+ }, [endX, endY]);
124
+ const positions = useDerivedValue(() => {
125
+ const from = fromPositions.value;
126
+ const to = toPositions.value;
127
+ const progress = positionsProgress.value;
128
+ if (to.length === 0) return [];
129
+ const count = Math.max(from.length, to.length);
130
+ const interpolated = Array.from({
131
+ length: count
132
+ }, (_, index) => {
133
+ var _from$Math$min, _to$Math$min;
134
+ const fromValue = (_from$Math$min = from[Math.min(index, from.length - 1)]) != null ? _from$Math$min : 0;
135
+ const toValue = (_to$Math$min = to[Math.min(index, to.length - 1)]) != null ? _to$Math$min : fromValue;
136
+ return fromValue + (toValue - fromValue) * progress;
137
+ });
138
+ return interpolated;
139
+ }, [fromPositions, toPositions, positionsProgress]);
140
+ if (!shouldRender) return null;
48
141
  return /*#__PURE__*/_jsx(LinearGradient, {
49
142
  colors: colors,
50
143
  end: end,
@@ -12,6 +12,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
12
12
  * Supports gradient for gradient effects on the dots and smooth data transitions via AnimatedPath.
13
13
  */
14
14
  export const DottedLine = /*#__PURE__*/memo(_ref => {
15
+ var _transitions$update;
15
16
  let {
16
17
  fill = 'none',
17
18
  stroke,
@@ -46,7 +47,9 @@ export const DottedLine = /*#__PURE__*/memo(_ref => {
46
47
  children: [/*#__PURE__*/_jsx(DashPathEffect, {
47
48
  intervals: dashIntervals
48
49
  }), gradient && /*#__PURE__*/_jsx(Gradient, {
50
+ animate: animate,
49
51
  gradient: gradient,
52
+ transition: (_transitions$update = transitions == null ? void 0 : transitions.update) != null ? _transitions$update : transition,
50
53
  xAxisId: xAxisId,
51
54
  yAxisId: yAxisId
52
55
  })]
@@ -1,4 +1,4 @@
1
- const _excluded = ["seriesId", "curve", "type", "areaType", "areaBaseline", "stroke", "strokeOpacity", "showArea", "LineComponent", "AreaComponent", "opacity", "points", "connectNulls", "transitions", "transition", "gradient"];
1
+ const _excluded = ["seriesId", "curve", "type", "areaType", "stroke", "strokeOpacity", "showArea", "LineComponent", "AreaComponent", "opacity", "points", "connectNulls", "transitions", "transition", "gradient"];
2
2
  function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
3
3
  function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
4
4
  import React, { memo, useMemo } from 'react';
@@ -20,7 +20,6 @@ export const Line = /*#__PURE__*/memo(_ref => {
20
20
  curve = 'bump',
21
21
  type = 'solid',
22
22
  areaType = 'gradient',
23
- areaBaseline,
24
23
  stroke: strokeProp,
25
24
  strokeOpacity,
26
25
  showArea,
@@ -114,7 +113,6 @@ export const Line = /*#__PURE__*/memo(_ref => {
114
113
  return /*#__PURE__*/_jsxs(_Fragment, {
115
114
  children: [showArea && /*#__PURE__*/_jsx(Area, {
116
115
  AreaComponent: AreaComponent,
117
- baseline: areaBaseline,
118
116
  connectNulls: connectNulls,
119
117
  curve: curve,
120
118
  fill: stroke,
@@ -1,6 +1,6 @@
1
1
  const _excluded = ["series", "showArea", "areaType", "type", "LineComponent", "AreaComponent", "curve", "points", "strokeWidth", "strokeOpacity", "connectNulls", "transition", "transitions", "opacity", "showXAxis", "showYAxis", "xAxis", "yAxis", "inset", "scrubberAccessibilityLabelStep", "layout", "children"],
2
- _excluded2 = ["scaleType", "data", "categoryPadding", "domain", "domainLimit", "range", "id"],
3
- _excluded3 = ["scaleType", "data", "categoryPadding", "domain", "domainLimit", "range", "id"],
2
+ _excluded2 = ["scaleType", "data", "categoryPadding", "domain", "domainLimit", "range", "baseline", "id"],
3
+ _excluded3 = ["scaleType", "data", "categoryPadding", "domain", "domainLimit", "range", "baseline", "id"],
4
4
  _excluded4 = ["id", "data", "label", "color", "xAxisId", "yAxisId"];
5
5
  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); }
6
6
  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; }
@@ -67,6 +67,7 @@ export const LineChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) =
67
67
  domain: xDomain,
68
68
  domainLimit: xDomainLimit,
69
69
  range: xRange,
70
+ baseline: xBaseline,
70
71
  id: xAxisId
71
72
  } = _ref2,
72
73
  xAxisVisualProps = _objectWithoutPropertiesLoose(_ref2, _excluded2);
@@ -78,6 +79,7 @@ export const LineChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) =
78
79
  domain: yDomain,
79
80
  domainLimit: yDomainLimit,
80
81
  range: yRange,
82
+ baseline: yBaseline,
81
83
  id: yAxisId
82
84
  } = _ref3,
83
85
  yAxisVisualProps = _objectWithoutPropertiesLoose(_ref3, _excluded3);
@@ -87,7 +89,8 @@ export const LineChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) =
87
89
  categoryPadding: xCategoryPadding,
88
90
  domain: xDomain,
89
91
  domainLimit: xDomainLimit,
90
- range: xRange
92
+ range: xRange,
93
+ baseline: xBaseline
91
94
  };
92
95
  const yAxisConfig = {
93
96
  scaleType: yScaleType,
@@ -95,7 +98,8 @@ export const LineChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) =
95
98
  categoryPadding: yCategoryPadding,
96
99
  domain: yDomain,
97
100
  domainLimit: yDomainLimit,
98
- range: yRange
101
+ range: yRange,
102
+ baseline: yBaseline
99
103
  };
100
104
  const categoryAxisData = layout === 'horizontal' ? yData : xData;
101
105
  const lineChartDataLength = useMemo(() => {
@@ -11,6 +11,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
11
11
  * Supports gradient for gradient effects and smooth data transitions via AnimatedPath.
12
12
  */
13
13
  export const SolidLine = /*#__PURE__*/memo(_ref => {
14
+ var _transitions$update;
14
15
  let {
15
16
  fill = 'none',
16
17
  stroke,
@@ -42,7 +43,9 @@ export const SolidLine = /*#__PURE__*/memo(_ref => {
42
43
  transitions: transitions
43
44
  }, props, {
44
45
  children: gradient && /*#__PURE__*/_jsx(Gradient, {
46
+ animate: animate,
45
47
  gradient: gradient,
48
+ transition: (_transitions$update = transitions == null ? void 0 : transitions.update) != null ? _transitions$update : transition,
46
49
  xAxisId: xAxisId,
47
50
  yAxisId: yAxisId
48
51
  })
@@ -1,6 +1,6 @@
1
1
  const _excluded = ["id"];
2
- function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
3
2
  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; }
3
+ 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); }
4
4
  import { useCallback, useMemo, useState } from 'react';
5
5
  import { getChartDomain, getChartRange, isValidBounds } from './chart';
6
6
  import { getPointOnScale } from './point';
@@ -46,6 +46,36 @@ export const toPointAnchor = placement => {
46
46
  * Axis configuration without computed bounds (used for input)
47
47
  */
48
48
 
49
+ const includeBaselineInBounds = (bounds, baseline) => {
50
+ if (baseline < bounds.min) return _extends({}, bounds, {
51
+ min: baseline
52
+ });
53
+ if (baseline > bounds.max) return _extends({}, bounds, {
54
+ max: baseline
55
+ });
56
+ return bounds;
57
+ };
58
+ export const withBaselineDomain = function (domain, baseline) {
59
+ if (baseline === void 0) {
60
+ baseline = 0;
61
+ }
62
+ if (typeof domain === 'function') return domain;
63
+ if ((domain == null ? void 0 : domain.min) !== undefined && (domain == null ? void 0 : domain.max) !== undefined) return domain;
64
+ const hasExplicitMin = (domain == null ? void 0 : domain.min) !== undefined;
65
+ const hasExplicitMax = (domain == null ? void 0 : domain.max) !== undefined;
66
+ return bounds => {
67
+ const resolvedBounds = {
68
+ min: hasExplicitMin ? domain == null ? void 0 : domain.min : bounds.min,
69
+ max: hasExplicitMax ? domain == null ? void 0 : domain.max : bounds.max
70
+ };
71
+ const baselineAdjustedBounds = includeBaselineInBounds(resolvedBounds, baseline);
72
+ return {
73
+ min: hasExplicitMin ? resolvedBounds.min : baselineAdjustedBounds.min,
74
+ max: hasExplicitMax ? resolvedBounds.max : baselineAdjustedBounds.max
75
+ };
76
+ };
77
+ };
78
+
49
79
  /**
50
80
  * Gets a D3 scale based on the cartesian axis configuration.
51
81
  * Handles both numeric (linear/log) and categorical (band) scales.
@@ -221,7 +251,7 @@ export const getCartesianAxisDomain = function (axisParam, series, axisType, lay
221
251
  // In vertical layout: X is category (index), Y is value (value)
222
252
  // In horizontal layout: Y is category (index), X is value (value)
223
253
  const isCategoryAxis = layout !== 'horizontal' && axisType === 'x' || layout === 'horizontal' && axisType === 'y';
224
- const seriesDomain = isCategoryAxis ? getChartDomain(series) : getChartRange(series);
254
+ const seriesDomain = isCategoryAxis ? getChartDomain(series) : getChartRange(series, layout, axisType === 'x' ? [axisParam] : [], axisType === 'y' ? [axisParam] : []);
225
255
 
226
256
  // If data sets the domain, use that instead of the series domain
227
257
  const preferredDataDomain = dataDomain != null ? dataDomain : seriesDomain;
@@ -246,8 +276,6 @@ export const getCartesianAxisDomain = function (axisParam, series, axisType, lay
246
276
  // Use the base domain as-is
247
277
  finalDomain = preferredDataDomain;
248
278
  }
249
-
250
- // Ensure we always return valid bounds with no undefined values
251
279
  return {
252
280
  min: (_finalDomain$min = finalDomain.min) != null ? _finalDomain$min : 0,
253
281
  max: (_finalDomain$max = finalDomain.max) != null ? _finalDomain$max : 0