@coinbase/cds-mobile-visualization 3.4.0-beta.22 → 3.4.0-beta.23

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 (100) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dts/chart/CartesianChart.d.ts +39 -7
  3. package/dts/chart/CartesianChart.d.ts.map +1 -1
  4. package/dts/chart/Path.d.ts.map +1 -1
  5. package/dts/chart/area/Area.d.ts +7 -0
  6. package/dts/chart/area/Area.d.ts.map +1 -1
  7. package/dts/chart/area/AreaChart.d.ts +5 -5
  8. package/dts/chart/area/AreaChart.d.ts.map +1 -1
  9. package/dts/chart/area/DottedArea.d.ts.map +1 -1
  10. package/dts/chart/area/GradientArea.d.ts.map +1 -1
  11. package/dts/chart/area/SolidArea.d.ts.map +1 -1
  12. package/dts/chart/axis/Axis.d.ts +3 -1
  13. package/dts/chart/axis/Axis.d.ts.map +1 -1
  14. package/dts/chart/axis/XAxis.d.ts +6 -0
  15. package/dts/chart/axis/XAxis.d.ts.map +1 -1
  16. package/dts/chart/axis/YAxis.d.ts +1 -0
  17. package/dts/chart/axis/YAxis.d.ts.map +1 -1
  18. package/dts/chart/bar/Bar.d.ts +4 -2
  19. package/dts/chart/bar/Bar.d.ts.map +1 -1
  20. package/dts/chart/bar/BarChart.d.ts +49 -9
  21. package/dts/chart/bar/BarChart.d.ts.map +1 -1
  22. package/dts/chart/bar/BarPlot.d.ts.map +1 -1
  23. package/dts/chart/bar/BarStack.d.ts +30 -9
  24. package/dts/chart/bar/BarStack.d.ts.map +1 -1
  25. package/dts/chart/bar/BarStackGroup.d.ts +1 -1
  26. package/dts/chart/bar/BarStackGroup.d.ts.map +1 -1
  27. package/dts/chart/bar/DefaultBar.d.ts.map +1 -1
  28. package/dts/chart/bar/DefaultBarStack.d.ts.map +1 -1
  29. package/dts/chart/gradient/Gradient.d.ts +5 -0
  30. package/dts/chart/gradient/Gradient.d.ts.map +1 -1
  31. package/dts/chart/line/DottedLine.d.ts.map +1 -1
  32. package/dts/chart/line/Line.d.ts +7 -0
  33. package/dts/chart/line/Line.d.ts.map +1 -1
  34. package/dts/chart/line/LineChart.d.ts +5 -5
  35. package/dts/chart/line/LineChart.d.ts.map +1 -1
  36. package/dts/chart/line/ReferenceLine.d.ts +1 -0
  37. package/dts/chart/line/ReferenceLine.d.ts.map +1 -1
  38. package/dts/chart/line/SolidLine.d.ts.map +1 -1
  39. package/dts/chart/point/Point.d.ts +7 -0
  40. package/dts/chart/point/Point.d.ts.map +1 -1
  41. package/dts/chart/scrubber/DefaultScrubberBeacon.d.ts.map +1 -1
  42. package/dts/chart/scrubber/DefaultScrubberLabel.d.ts +2 -1
  43. package/dts/chart/scrubber/DefaultScrubberLabel.d.ts.map +1 -1
  44. package/dts/chart/scrubber/Scrubber.d.ts +8 -0
  45. package/dts/chart/scrubber/Scrubber.d.ts.map +1 -1
  46. package/dts/chart/scrubber/ScrubberBeaconGroup.d.ts.map +1 -1
  47. package/dts/chart/scrubber/ScrubberProvider.d.ts.map +1 -1
  48. package/dts/chart/utils/axis.d.ts +20 -9
  49. package/dts/chart/utils/axis.d.ts.map +1 -1
  50. package/dts/chart/utils/bar.d.ts +4 -3
  51. package/dts/chart/utils/bar.d.ts.map +1 -1
  52. package/dts/chart/utils/chart.d.ts +13 -0
  53. package/dts/chart/utils/chart.d.ts.map +1 -1
  54. package/dts/chart/utils/context.d.ts +21 -6
  55. package/dts/chart/utils/context.d.ts.map +1 -1
  56. package/dts/chart/utils/gradient.d.ts +3 -1
  57. package/dts/chart/utils/gradient.d.ts.map +1 -1
  58. package/dts/chart/utils/path.d.ts +20 -0
  59. package/dts/chart/utils/path.d.ts.map +1 -1
  60. package/dts/chart/utils/point.d.ts +7 -0
  61. package/dts/chart/utils/point.d.ts.map +1 -1
  62. package/esm/chart/CartesianChart.js +107 -68
  63. package/esm/chart/Path.js +10 -7
  64. package/esm/chart/area/Area.js +19 -9
  65. package/esm/chart/area/AreaChart.js +11 -9
  66. package/esm/chart/area/DottedArea.js +11 -6
  67. package/esm/chart/area/GradientArea.js +11 -6
  68. package/esm/chart/area/SolidArea.js +3 -1
  69. package/esm/chart/area/__stories__/AreaChart.stories.js +30 -2
  70. package/esm/chart/axis/XAxis.js +14 -21
  71. package/esm/chart/axis/YAxis.js +4 -3
  72. package/esm/chart/bar/Bar.js +9 -5
  73. package/esm/chart/bar/BarChart.js +34 -31
  74. package/esm/chart/bar/BarPlot.js +7 -5
  75. package/esm/chart/bar/BarStack.js +176 -36
  76. package/esm/chart/bar/BarStackGroup.js +37 -27
  77. package/esm/chart/bar/DefaultBar.js +24 -8
  78. package/esm/chart/bar/DefaultBarStack.js +24 -10
  79. package/esm/chart/bar/__stories__/BarChart.stories.js +99 -3
  80. package/esm/chart/gradient/Gradient.js +2 -1
  81. package/esm/chart/line/DottedLine.js +3 -1
  82. package/esm/chart/line/Line.js +32 -19
  83. package/esm/chart/line/LineChart.js +9 -8
  84. package/esm/chart/line/SolidLine.js +3 -1
  85. package/esm/chart/line/__stories__/LineChart.stories.js +31 -0
  86. package/esm/chart/point/Point.js +2 -1
  87. package/esm/chart/scrubber/DefaultScrubberBeacon.js +1 -1
  88. package/esm/chart/scrubber/DefaultScrubberLabel.js +26 -10
  89. package/esm/chart/scrubber/Scrubber.js +47 -21
  90. package/esm/chart/scrubber/ScrubberBeaconGroup.js +24 -20
  91. package/esm/chart/scrubber/ScrubberProvider.js +29 -24
  92. package/esm/chart/scrubber/__stories__/Scrubber.stories.js +135 -1
  93. package/esm/chart/utils/axis.js +42 -14
  94. package/esm/chart/utils/bar.js +5 -4
  95. package/esm/chart/utils/chart.js +18 -5
  96. package/esm/chart/utils/context.js +7 -0
  97. package/esm/chart/utils/gradient.js +8 -4
  98. package/esm/chart/utils/path.js +90 -61
  99. package/esm/chart/utils/point.js +28 -18
  100. package/package.json +5 -5
@@ -1,4 +1,4 @@
1
- const _excluded = ["series", "yAxisId", "stackIndex", "totalStacks", "barPadding"];
1
+ const _excluded = ["series", "xAxisId", "yAxisId", "stackIndex", "totalStacks", "barPadding"];
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 { memo, useMemo, createElement as _createElement } from 'react';
@@ -12,6 +12,7 @@ import { BarStack } from './BarStack';
12
12
  export const BarStackGroup = /*#__PURE__*/memo(_ref => {
13
13
  let {
14
14
  series,
15
+ xAxisId = defaultAxisId,
15
16
  yAxisId = defaultAxisId,
16
17
  stackIndex,
17
18
  totalStacks,
@@ -19,61 +20,70 @@ export const BarStackGroup = /*#__PURE__*/memo(_ref => {
19
20
  } = _ref,
20
21
  props = _objectWithoutPropertiesLoose(_ref, _excluded);
21
22
  const {
23
+ layout,
22
24
  getXScale,
23
25
  getYScale,
24
26
  drawingArea,
25
27
  dataLength
26
28
  } = useCartesianChartContext();
27
- const xScale = getXScale();
29
+ const xScale = getXScale(xAxisId);
28
30
  const yScale = getYScale(yAxisId);
29
31
  const stackConfigs = useMemo(() => {
30
32
  if (!xScale || !yScale || !drawingArea || dataLength === 0) return [];
31
- if (!isCategoricalScale(xScale)) {
33
+ const indexScale = layout !== 'horizontal' ? xScale : yScale;
34
+ if (!isCategoricalScale(indexScale)) {
32
35
  return [];
33
36
  }
34
- const categoryWidth = xScale.bandwidth();
37
+ const categoryWidth = indexScale.bandwidth();
35
38
 
36
- // Calculate width for each stack within a category
37
- // Only apply barPadding when there are multiple stacks
38
- const gapWidth = totalStacks > 1 ? categoryWidth * barPadding / (totalStacks - 1) : 0;
39
- const barWidth = categoryWidth / totalStacks - getBarSizeAdjustment(totalStacks, gapWidth);
39
+ // Calculate thickness for each stack within a category.
40
+ const gapSize = totalStacks > 1 ? categoryWidth * barPadding / (totalStacks - 1) : 0;
41
+ const stackThickness = categoryWidth / totalStacks - getBarSizeAdjustment(totalStacks, gapSize);
40
42
  const configs = [];
41
43
 
42
- // Calculate position for each category
43
- // todo: look at using xDomain for this instead of dataLength
44
+ // Calculate position for each category.
44
45
  for (let categoryIndex = 0; categoryIndex < dataLength; categoryIndex++) {
45
- // Get x position for this category
46
- const categoryX = xScale(categoryIndex);
47
- if (categoryX !== undefined) {
48
- // Calculate x position for this specific stack within the category
49
- const stackX = categoryX + stackIndex * (barWidth + gapWidth);
46
+ // Get position for this category along the index axis.
47
+ const categoryPos = indexScale(categoryIndex);
48
+ if (categoryPos !== undefined) {
49
+ // Calculate position for this specific stack within the category.
50
+ const stackPos = categoryPos + stackIndex * (stackThickness + gapSize);
50
51
  configs.push({
51
52
  categoryIndex,
52
- x: stackX,
53
- width: barWidth
53
+ indexPos: stackPos,
54
+ thickness: stackThickness
54
55
  });
55
56
  }
56
57
  }
57
58
  return configs;
58
- }, [xScale, yScale, drawingArea, dataLength, stackIndex, totalStacks, barPadding]);
59
- if (xScale && !isCategoricalScale(xScale)) {
60
- throw new Error('BarStackGroup requires a band scale for x-axis. See https://cds.coinbase.com/components/charts/XAxis/#scale-type');
59
+ }, [xScale, yScale, drawingArea, dataLength, layout, totalStacks, barPadding, stackIndex]);
60
+ const indexScaleComputed = layout !== 'horizontal' ? xScale : yScale;
61
+ const valueScaleComputed = layout !== 'horizontal' ? yScale : xScale;
62
+ if (indexScaleComputed && !isCategoricalScale(indexScaleComputed)) {
63
+ throw new Error("BarStackGroup requires a band scale for " + (layout !== 'horizontal' ? 'x-axis' : 'y-axis') + ". See https://cds.coinbase.com/components/charts/" + (layout !== 'horizontal' ? 'XAxis' : 'YAxis') + "/#scale-type");
61
64
  }
62
- if (!yScale || !drawingArea || stackConfigs.length === 0) return;
63
- return stackConfigs.map(_ref2 => {
65
+ if (!indexScaleComputed || !valueScaleComputed || !drawingArea || stackConfigs.length === 0) return;
66
+
67
+ // In horizontal layout, render stacks in reverse order so top rows (lower categoryIndex)
68
+ // appear on top. Otherwise bottom rows would overlap and obscure top rows during animation.
69
+ const orderedConfigs = layout === 'horizontal' ? [...stackConfigs].reverse() : stackConfigs;
70
+ return orderedConfigs.map(_ref2 => {
64
71
  let {
65
72
  categoryIndex,
66
- x,
67
- width
73
+ indexPos,
74
+ thickness
68
75
  } = _ref2;
69
76
  return /*#__PURE__*/_createElement(BarStack, _extends({}, props, {
70
77
  key: "stack-" + stackIndex + "-category-" + categoryIndex,
71
78
  categoryIndex: categoryIndex,
79
+ indexPos: indexPos,
80
+ indexScale: indexScaleComputed,
72
81
  rect: drawingArea,
73
82
  series: series,
74
- width: width,
75
- x: x,
76
- yScale: yScale
83
+ thickness: thickness,
84
+ valueScale: valueScaleComputed,
85
+ xAxisId: xAxisId,
86
+ yAxisId: yAxisId
77
87
  }));
78
88
  });
79
89
  });
@@ -22,23 +22,39 @@ export const DefaultBar = /*#__PURE__*/memo(_ref => {
22
22
  fillOpacity = 1,
23
23
  stroke,
24
24
  strokeWidth,
25
- originY,
25
+ origin,
26
26
  transitions,
27
27
  transition
28
28
  } = _ref;
29
29
  const {
30
30
  animate,
31
- drawingArea
31
+ drawingArea,
32
+ layout
32
33
  } = useCartesianChartContext();
33
34
  const theme = useTheme();
34
35
  const defaultFill = fill || theme.color.fgPrimary;
35
- const normalizedX = useMemo(() => drawingArea.width > 0 ? (x - drawingArea.x) / drawingArea.width : 0, [x, drawingArea.x, drawingArea.width]);
36
- const enterTransition = useMemo(() => withStaggerDelayTransition(getTransition(transitions == null ? void 0 : transitions.enter, animate, defaultBarEnterTransition), normalizedX), [transitions == null ? void 0 : transitions.enter, animate, normalizedX]);
37
- const updateTransition = useMemo(() => withStaggerDelayTransition(getTransition((transitions == null ? void 0 : transitions.update) !== undefined ? transitions.update : transition, animate, defaultTransition), normalizedX), [transitions == null ? void 0 : transitions.update, transition, animate, normalizedX]);
36
+
37
+ // For vertical layout, stagger by x (category axis). For horizontal, stagger by y (category axis).
38
+ const normalizedStagger = useMemo(() => {
39
+ const barsGrowVertically = layout !== 'horizontal';
40
+ if (barsGrowVertically) {
41
+ return drawingArea.width > 0 ? (x - drawingArea.x) / drawingArea.width : 0;
42
+ }
43
+ return drawingArea.height > 0 ? (y - drawingArea.y) / drawingArea.height : 0;
44
+ }, [layout, x, y, drawingArea.x, drawingArea.y, drawingArea.width, drawingArea.height]);
45
+ const enterTransition = useMemo(() => withStaggerDelayTransition(getTransition(transitions == null ? void 0 : transitions.enter, animate, defaultBarEnterTransition), normalizedStagger), [transitions == null ? void 0 : transitions.enter, animate, normalizedStagger]);
46
+ const updateTransition = useMemo(() => withStaggerDelayTransition(getTransition((transitions == null ? void 0 : transitions.update) !== undefined ? transitions.update : transition, animate, defaultTransition), normalizedStagger), [transitions == null ? void 0 : transitions.update, transition, animate, normalizedStagger]);
38
47
  const initialPath = useMemo(() => {
39
- const baselineY = originY != null ? originY : y + height;
40
- return getBarPath(x, baselineY, width, 1, borderRadius, !!roundTop, !!roundBottom);
41
- }, [x, originY, y, height, width, borderRadius, roundTop, roundBottom]);
48
+ if (!animate) return undefined;
49
+ const minSize = 1;
50
+ const barsGrowVertically = layout !== 'horizontal';
51
+ const baseline = origin != null ? origin : barsGrowVertically ? y + height : x;
52
+ const initialX = barsGrowVertically ? x : baseline;
53
+ const initialY = barsGrowVertically ? baseline : y;
54
+ const initialWidth = barsGrowVertically ? width : minSize;
55
+ const initialHeight = barsGrowVertically ? minSize : height;
56
+ return getBarPath(initialX, initialY, initialWidth, initialHeight, borderRadius, !!roundTop, !!roundBottom, layout);
57
+ }, [animate, layout, x, y, origin, width, height, borderRadius, roundTop, roundBottom]);
42
58
  return /*#__PURE__*/_jsx(Path, {
43
59
  animate: animate,
44
60
  clipPath: null,
@@ -24,24 +24,38 @@ export const DefaultBarStack = /*#__PURE__*/memo(_ref => {
24
24
  } = _ref;
25
25
  const {
26
26
  animate,
27
- drawingArea
27
+ drawingArea,
28
+ layout
28
29
  } = useCartesianChartContext();
29
30
 
30
- // Compute normalized x position for stagger delay calculation
31
- const normalizedX = useMemo(() => drawingArea.width > 0 ? (x - drawingArea.x) / drawingArea.width : 0, [x, drawingArea.x, drawingArea.width]);
32
- const enterTransition = useMemo(() => withStaggerDelayTransition(getTransition(transitions == null ? void 0 : transitions.enter, animate, defaultBarEnterTransition), normalizedX), [animate, transitions == null ? void 0 : transitions.enter, normalizedX]);
33
- const updateTransition = useMemo(() => withStaggerDelayTransition(getTransition((transitions == null ? void 0 : transitions.update) !== undefined ? transitions.update : transition, animate, defaultTransition), normalizedX), [animate, transitions == null ? void 0 : transitions.update, transition, normalizedX]);
31
+ // For vertical layout, stagger by x (category axis). For horizontal, stagger by y (category axis).
32
+ const normalizedStagger = useMemo(() => {
33
+ const barsGrowVertically = layout !== 'horizontal';
34
+ if (barsGrowVertically) {
35
+ return drawingArea.width > 0 ? (x - drawingArea.x) / drawingArea.width : 0;
36
+ }
37
+ return drawingArea.height > 0 ? (y - drawingArea.y) / drawingArea.height : 0;
38
+ }, [layout, x, y, drawingArea.x, drawingArea.y, drawingArea.width, drawingArea.height]);
39
+ const enterTransition = useMemo(() => withStaggerDelayTransition(getTransition(transitions == null ? void 0 : transitions.enter, animate, defaultBarEnterTransition), normalizedStagger), [animate, transitions == null ? void 0 : transitions.enter, normalizedStagger]);
40
+ const updateTransition = useMemo(() => withStaggerDelayTransition(getTransition((transitions == null ? void 0 : transitions.update) !== undefined ? transitions.update : transition, animate, defaultTransition), normalizedStagger), [animate, transitions == null ? void 0 : transitions.update, transition, normalizedStagger]);
34
41
 
35
42
  // Generate target clip path (full bar)
36
43
  const targetPath = useMemo(() => {
37
- return getBarPath(x, y, width, height, borderRadius, roundTop, roundBottom);
38
- }, [x, y, width, height, borderRadius, roundTop, roundBottom]);
44
+ return getBarPath(x, y, width, height, borderRadius, roundTop, roundBottom, layout);
45
+ }, [x, y, width, height, borderRadius, roundTop, roundBottom, layout]);
39
46
 
40
47
  // Initial clip path for entry animation (bar at baseline with minimal height)
41
48
  const initialPath = useMemo(() => {
42
- const baselineY = yOrigin != null ? yOrigin : y + height;
43
- return getBarPath(x, baselineY, width, 1, borderRadius, roundTop, roundBottom);
44
- }, [x, yOrigin, y, height, width, borderRadius, roundTop, roundBottom]);
49
+ if (!animate) return undefined;
50
+ const barsGrowVertically = layout !== 'horizontal';
51
+ const baseline = yOrigin != null ? yOrigin : barsGrowVertically ? y + height : x;
52
+ const minSize = 1;
53
+ const initialX = barsGrowVertically ? x : baseline;
54
+ const initialY = barsGrowVertically ? baseline : y;
55
+ const initialWidth = barsGrowVertically ? width : minSize;
56
+ const initialHeight = barsGrowVertically ? minSize : height;
57
+ return getBarPath(initialX, initialY, initialWidth, initialHeight, borderRadius, roundTop, roundBottom, layout);
58
+ }, [animate, layout, x, yOrigin, y, height, width, borderRadius, roundTop, roundBottom]);
45
59
  const animatedClipPath = usePathTransition({
46
60
  currentPath: targetPath,
47
61
  initialPath,
@@ -1,6 +1,6 @@
1
1
  const _excluded = ["children"],
2
2
  _excluded2 = ["animate"],
3
- _excluded3 = ["x", "y", "width", "height", "originY", "dataX"],
3
+ _excluded3 = ["x", "y", "width", "height", "dataX"],
4
4
  _excluded4 = ["data", "height"];
5
5
  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; }
6
6
  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); }
@@ -114,7 +114,7 @@ const CustomBarStackComponent = /*#__PURE__*/memo(_ref => {
114
114
  borderRadius: 1000,
115
115
  fill: theme.color.bgTertiary,
116
116
  height: diameter,
117
- originY: props.y,
117
+ origin: props.y,
118
118
  width: diameter,
119
119
  x: props.x,
120
120
  y: props.y - diameter
@@ -975,7 +975,7 @@ const SunlightChartInner = /*#__PURE__*/memo(_ref10 => {
975
975
  type: 'spring',
976
976
  stiffness: 700,
977
977
  damping: 40,
978
- staggerDelay: 1
978
+ staggerDelay: 1000
979
979
  }
980
980
  }
981
981
  })]
@@ -1029,6 +1029,96 @@ const PriceRange = () => {
1029
1029
  }
1030
1030
  });
1031
1031
  };
1032
+ const HorizontalBarChart = () => {
1033
+ const labels = ['BTC', 'ETH', 'SOL', 'ADA'];
1034
+ const allocation = [42, 28, 18, 12];
1035
+ return /*#__PURE__*/_jsx(BarChart, {
1036
+ showXAxis: true,
1037
+ showYAxis: true,
1038
+ height: 220,
1039
+ layout: "horizontal",
1040
+ series: [{
1041
+ id: 'allocation',
1042
+ data: allocation,
1043
+ color: assets.btc.color
1044
+ }],
1045
+ xAxis: {
1046
+ domain: {
1047
+ min: 0,
1048
+ max: 50
1049
+ },
1050
+ tickLabelFormatter: value => value + "%"
1051
+ },
1052
+ yAxis: {
1053
+ data: labels,
1054
+ scaleType: 'band'
1055
+ }
1056
+ });
1057
+ };
1058
+ const PopulationPyramid = () => {
1059
+ const theme = useTheme();
1060
+ const ageGroups = ['100+ yrs', '95-99 yrs', '90-94 yrs', '85-89 yrs', '80-84 yrs', '75-79 yrs', '70-74 yrs', '65-69 yrs', '60-64 yrs', '55-59 yrs', '50-54 yrs', '45-49 yrs', '40-44 yrs', '35-39 yrs', '30-34 yrs', '25-29 yrs', '20-24 yrs', '15-19 yrs', '10-14 yrs', '5-9 yrs', '0-4 yrs'];
1061
+ const malePopulation = [14587, 48604, 83560, 128957, 184152, 248505, 498683, 706420, 852333, 939629, 1002195, 1001264, 960282, 1161371, 1105023, 1061755, 1019343, 1023264, 1026330, 984773, 944071];
1062
+ const femalePopulation = [14122, 46974, 80768, 124663, 178043, 240293, 482271, 683270, 824525, 909115, 969807, 969070, 929571, 1122380, 1068050, 1026356, 985483, 989404, 992505, 952453, 913222];
1063
+ const numberWithSuffixFormatter = useMemo(() => new Intl.NumberFormat('en-US', {
1064
+ notation: 'compact'
1065
+ }), []);
1066
+ const tickLabelFormatter = useCallback(value => numberWithSuffixFormatter.format(Math.abs(value)), [numberWithSuffixFormatter]);
1067
+ const domainSymmetric = useCallback(bounds => {
1068
+ const extremum = Math.max(-bounds.min, bounds.max);
1069
+ const roundedExtremum = Math.ceil(extremum / 100000) * 100000;
1070
+ return {
1071
+ min: -roundedExtremum,
1072
+ max: roundedExtremum
1073
+ };
1074
+ }, []);
1075
+ const series = [{
1076
+ id: 'male',
1077
+ label: 'Male',
1078
+ data: malePopulation.map(population => -population),
1079
+ color: "rgb(" + theme.spectrum.blue40 + ")",
1080
+ stackId: 'population'
1081
+ }, {
1082
+ id: 'female',
1083
+ label: 'Female',
1084
+ data: femalePopulation,
1085
+ color: "rgb(" + theme.spectrum.pink40 + ")",
1086
+ stackId: 'population'
1087
+ }];
1088
+ return /*#__PURE__*/_jsx(VStack, {
1089
+ gap: 2,
1090
+ children: /*#__PURE__*/_jsx(BarChart, {
1091
+ showXAxis: true,
1092
+ showYAxis: true,
1093
+ stacked: true,
1094
+ borderRadius: 2,
1095
+ height: 550,
1096
+ inset: 0,
1097
+ layout: "horizontal",
1098
+ series: series,
1099
+ xAxis: {
1100
+ domain: domainSymmetric,
1101
+ GridLineComponent: ThinSolidLine,
1102
+ showGrid: true,
1103
+ showLine: true,
1104
+ showTickMarks: true,
1105
+ tickLabelFormatter
1106
+ },
1107
+ yAxis: {
1108
+ bandTickMarkPlacement: 'edges',
1109
+ data: ageGroups,
1110
+ position: 'left',
1111
+ showLine: true,
1112
+ showTickMarks: true,
1113
+ width: 80
1114
+ },
1115
+ children: /*#__PURE__*/_jsx(ReferenceLine, {
1116
+ LineComponent: SolidLine,
1117
+ dataX: 0
1118
+ })
1119
+ })
1120
+ });
1121
+ };
1032
1122
  function ExampleNavigator() {
1033
1123
  const [currentIndex, setCurrentIndex] = useState(0);
1034
1124
  const examples = useMemo(() => [{
@@ -1093,6 +1183,12 @@ function ExampleNavigator() {
1093
1183
  }, {
1094
1184
  title: 'Price Range',
1095
1185
  component: /*#__PURE__*/_jsx(PriceRange, {})
1186
+ }, {
1187
+ title: 'Horizontal Layout',
1188
+ component: /*#__PURE__*/_jsx(HorizontalBarChart, {})
1189
+ }, {
1190
+ title: 'Population Pyramid',
1191
+ component: /*#__PURE__*/_jsx(PopulationPyramid, {})
1096
1192
  }], []);
1097
1193
  const currentExample = examples[currentIndex];
1098
1194
  const handlePrevious = useCallback(() => {
@@ -16,10 +16,11 @@ export const Gradient = /*#__PURE__*/memo(_ref => {
16
16
  var _gradient$axis;
17
17
  let {
18
18
  gradient,
19
+ xAxisId,
19
20
  yAxisId
20
21
  } = _ref;
21
22
  const context = useCartesianChartContext();
22
- const xScale = context.getXScale();
23
+ const xScale = context.getXScale(xAxisId);
23
24
  const yScale = context.getYScale(yAxisId);
24
25
  const axis = (_gradient$axis = gradient.axis) != null ? _gradient$axis : 'y';
25
26
  const scale = axis === 'x' ? xScale : yScale;
@@ -1,4 +1,4 @@
1
- const _excluded = ["fill", "stroke", "dashIntervals", "strokeCap", "strokeJoin", "strokeOpacity", "strokeWidth", "gradient", "yAxisId", "d", "animate", "transitions", "transition"];
1
+ const _excluded = ["fill", "stroke", "dashIntervals", "strokeCap", "strokeJoin", "strokeOpacity", "strokeWidth", "gradient", "xAxisId", "yAxisId", "d", "animate", "transitions", "transition"];
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 { memo } from 'react';
@@ -21,6 +21,7 @@ export const DottedLine = /*#__PURE__*/memo(_ref => {
21
21
  strokeOpacity = 1,
22
22
  strokeWidth = 2,
23
23
  gradient,
24
+ xAxisId,
24
25
  yAxisId,
25
26
  d,
26
27
  animate,
@@ -46,6 +47,7 @@ export const DottedLine = /*#__PURE__*/memo(_ref => {
46
47
  intervals: dashIntervals
47
48
  }), gradient && /*#__PURE__*/_jsx(Gradient, {
48
49
  gradient: gradient,
50
+ xAxisId: xAxisId,
49
51
  yAxisId: yAxisId
50
52
  })]
51
53
  }));
@@ -36,36 +36,47 @@ export const Line = /*#__PURE__*/memo(_ref => {
36
36
  props = _objectWithoutPropertiesLoose(_ref, _excluded);
37
37
  const theme = useTheme();
38
38
  const {
39
+ layout,
39
40
  animate,
40
41
  getSeries,
41
42
  getSeriesData,
42
43
  getXScale,
43
44
  getYScale,
44
- getXAxis
45
+ getXAxis,
46
+ getYAxis
45
47
  } = useCartesianChartContext();
46
48
  const matchedSeries = useMemo(() => getSeries(seriesId), [getSeries, seriesId]);
47
49
  const gradient = useMemo(() => gradientProp != null ? gradientProp : matchedSeries == null ? void 0 : matchedSeries.gradient, [gradientProp, matchedSeries == null ? void 0 : matchedSeries.gradient]);
48
50
  const sourceData = useMemo(() => getSeriesData(seriesId), [getSeriesData, seriesId]);
49
- const xAxis = useMemo(() => getXAxis(), [getXAxis]);
50
- const xScale = useMemo(() => getXScale(), [getXScale]);
51
+ const xAxis = useMemo(() => getXAxis(matchedSeries == null ? void 0 : matchedSeries.xAxisId), [getXAxis, matchedSeries == null ? void 0 : matchedSeries.xAxisId]);
52
+ const xScale = useMemo(() => getXScale(matchedSeries == null ? void 0 : matchedSeries.xAxisId), [getXScale, matchedSeries == null ? void 0 : matchedSeries.xAxisId]);
51
53
  const yScale = useMemo(() => getYScale(matchedSeries == null ? void 0 : matchedSeries.yAxisId), [getYScale, matchedSeries == null ? void 0 : matchedSeries.yAxisId]);
54
+ const yAxis = useMemo(() => getYAxis(matchedSeries == null ? void 0 : matchedSeries.yAxisId), [getYAxis, matchedSeries == null ? void 0 : matchedSeries.yAxisId]);
52
55
 
53
56
  // Convert sourceData to number array (line only supports numbers, not tuples)
54
57
  const chartData = useMemo(() => getLineData(sourceData), [sourceData]);
58
+ const categoryAxisIsX = useMemo(() => {
59
+ return layout !== 'horizontal';
60
+ }, [layout]);
61
+ const categoryAxis = useMemo(() => {
62
+ return categoryAxisIsX ? xAxis : yAxis;
63
+ }, [categoryAxisIsX, xAxis, yAxis]);
55
64
  const path = useMemo(() => {
56
65
  if (!xScale || !yScale || chartData.length === 0) return '';
57
66
 
58
- // Get numeric x-axis data if available
59
- const xData = xAxis != null && xAxis.data && Array.isArray(xAxis.data) && typeof xAxis.data[0] === 'number' ? xAxis.data : undefined;
67
+ // Get numeric category-axis data if available.
68
+ const indexData = categoryAxis != null && categoryAxis.data && Array.isArray(categoryAxis.data) && typeof categoryAxis.data[0] === 'number' ? categoryAxis.data : undefined;
60
69
  return getLinePath({
61
70
  data: chartData,
62
71
  xScale,
63
72
  yScale,
64
73
  curve,
65
- xData,
66
- connectNulls
74
+ xData: categoryAxisIsX ? indexData : undefined,
75
+ yData: !categoryAxisIsX ? indexData : undefined,
76
+ connectNulls,
77
+ layout
67
78
  });
68
- }, [chartData, xScale, yScale, curve, xAxis == null ? void 0 : xAxis.data, connectNulls]);
79
+ }, [xScale, yScale, chartData, categoryAxis, curve, categoryAxisIsX, connectNulls, layout]);
69
80
  const LineComponent = useMemo(() => {
70
81
  if (SelectedLineComponent) {
71
82
  return SelectedLineComponent;
@@ -80,10 +91,10 @@ export const Line = /*#__PURE__*/memo(_ref => {
80
91
 
81
92
  // Get series color for stroke
82
93
  const stroke = (_ref2 = strokeProp != null ? strokeProp : matchedSeries == null ? void 0 : matchedSeries.color) != null ? _ref2 : theme.color.fgPrimary;
83
- const xData = useMemo(() => {
84
- const data = xAxis == null ? void 0 : xAxis.data;
94
+ const categoryData = useMemo(() => {
95
+ const data = categoryAxis == null ? void 0 : categoryAxis.data;
85
96
  return data && Array.isArray(data) && data.length > 0 && typeof data[0] === 'number' ? data : null;
86
- }, [xAxis == null ? void 0 : xAxis.data]);
97
+ }, [categoryAxis]);
87
98
  const gradientConfig = useMemo(() => {
88
99
  if (!gradient || !xScale || !yScale) return;
89
100
  const gradientScale = gradient.axis === 'x' ? xScale : yScale;
@@ -120,17 +131,18 @@ export const Line = /*#__PURE__*/memo(_ref => {
120
131
  strokeOpacity: strokeOpacity != null ? strokeOpacity : opacity,
121
132
  transition: transition,
122
133
  transitions: transitions,
134
+ xAxisId: matchedSeries == null ? void 0 : matchedSeries.xAxisId,
123
135
  yAxisId: matchedSeries == null ? void 0 : matchedSeries.yAxisId
124
136
  }, props)), points && /*#__PURE__*/_jsx(Group, {
125
137
  children: chartData.map((value, index) => {
126
138
  if (value === null) return;
127
- const xValue = xData && xData[index] !== undefined ? xData[index] : index;
139
+ const indexValue = categoryData && categoryData[index] !== undefined ? categoryData[index] : index;
128
140
  let pointFill = stroke;
129
141
  if (gradientConfig && gradient) {
130
142
  var _gradient$axis;
131
- // Use the appropriate data value based on gradient axis
132
- const axis = (_gradient$axis = gradient.axis) != null ? _gradient$axis : 'y';
133
- const dataValue = axis === 'x' ? xValue : value;
143
+ // Match gradient sampling to the chart axis roles for each layout.
144
+ const gradientAxis = (_gradient$axis = gradient.axis) != null ? _gradient$axis : 'y';
145
+ const dataValue = gradientAxis === 'x' ? categoryAxisIsX ? indexValue : value : categoryAxisIsX ? value : indexValue;
134
146
  const evaluatedColor = evaluateGradientAtValue(gradientConfig.stops, dataValue, gradientConfig.scale);
135
147
  if (evaluatedColor) {
136
148
  // Apply gradient color to fill if not explicitly set
@@ -140,9 +152,10 @@ export const Line = /*#__PURE__*/memo(_ref => {
140
152
 
141
153
  // Build defaults that would be passed to Point
142
154
  const defaults = {
143
- dataX: xValue,
144
- dataY: value,
155
+ dataX: categoryAxisIsX ? indexValue : value,
156
+ dataY: categoryAxisIsX ? value : indexValue,
145
157
  fill: pointFill,
158
+ xAxisId: matchedSeries == null ? void 0 : matchedSeries.xAxisId,
146
159
  yAxisId: matchedSeries == null ? void 0 : matchedSeries.yAxisId,
147
160
  opacity
148
161
  };
@@ -152,7 +165,7 @@ export const Line = /*#__PURE__*/memo(_ref => {
152
165
  return /*#__PURE__*/_jsx(Point, _extends({
153
166
  transition: transition,
154
167
  transitions: transitions
155
- }, defaults), seriesId + "-" + xValue);
168
+ }, defaults), seriesId + "-" + index);
156
169
  }
157
170
 
158
171
  // Call the function with defaults
@@ -162,7 +175,7 @@ export const Line = /*#__PURE__*/memo(_ref => {
162
175
  return /*#__PURE__*/_jsx(Point, _extends({
163
176
  transition: transition,
164
177
  transitions: transitions
165
- }, defaults, pointConfig), seriesId + "-" + xValue);
178
+ }, defaults, pointConfig), seriesId + "-" + index);
166
179
  })
167
180
  })]
168
181
  });
@@ -1,14 +1,13 @@
1
1
  const _excluded = ["series", "showArea", "areaType", "type", "LineComponent", "AreaComponent", "curve", "points", "strokeWidth", "strokeOpacity", "connectNulls", "transition", "transitions", "opacity", "showXAxis", "showYAxis", "xAxis", "yAxis", "inset", "children"],
2
- _excluded2 = ["scaleType", "data", "categoryPadding", "domain", "domainLimit", "range"],
2
+ _excluded2 = ["scaleType", "data", "categoryPadding", "domain", "domainLimit", "range", "id"],
3
3
  _excluded3 = ["scaleType", "data", "categoryPadding", "domain", "domainLimit", "range", "id"],
4
- _excluded4 = ["id", "data", "label", "color", "yAxisId"];
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; }
7
7
  import { forwardRef, memo, useMemo } from 'react';
8
8
  import { XAxis } from '../axis/XAxis';
9
9
  import { YAxis } from '../axis/YAxis';
10
10
  import { CartesianChart } from '../CartesianChart';
11
- import { defaultChartInset, getChartInset } from '../utils';
12
11
  import { Line } from './Line';
13
12
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
14
13
  export const LineChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) => {
@@ -35,8 +34,6 @@ export const LineChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) =
35
34
  children
36
35
  } = _ref,
37
36
  chartProps = _objectWithoutPropertiesLoose(_ref, _excluded);
38
- const calculatedInset = useMemo(() => getChartInset(inset, defaultChartInset), [inset]);
39
-
40
37
  // Convert LineSeries to Series for Chart context
41
38
  const chartSeries = useMemo(() => {
42
39
  return series == null ? void 0 : series.map(s => ({
@@ -44,6 +41,7 @@ export const LineChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) =
44
41
  data: s.data,
45
42
  label: s.label,
46
43
  color: s.color,
44
+ xAxisId: s.xAxisId,
47
45
  yAxisId: s.yAxisId,
48
46
  stackId: s.stackId,
49
47
  gradient: s.gradient,
@@ -59,7 +57,8 @@ export const LineChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) =
59
57
  categoryPadding: xCategoryPadding,
60
58
  domain: xDomain,
61
59
  domainLimit: xDomainLimit,
62
- range: xRange
60
+ range: xRange,
61
+ id: xAxisId
63
62
  } = _ref2,
64
63
  xAxisVisualProps = _objectWithoutPropertiesLoose(_ref2, _excluded2);
65
64
  const _ref3 = yAxis || {},
@@ -91,11 +90,13 @@ export const LineChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) =
91
90
  };
92
91
  return /*#__PURE__*/_jsxs(CartesianChart, _extends({}, chartProps, {
93
92
  ref: ref,
94
- inset: calculatedInset,
93
+ inset: inset,
95
94
  series: chartSeries,
96
95
  xAxis: xAxisConfig,
97
96
  yAxis: yAxisConfig,
98
- children: [showXAxis && /*#__PURE__*/_jsx(XAxis, _extends({}, xAxisVisualProps)), showYAxis && /*#__PURE__*/_jsx(YAxis, _extends({
97
+ children: [showXAxis && /*#__PURE__*/_jsx(XAxis, _extends({
98
+ axisId: xAxisId
99
+ }, xAxisVisualProps)), showYAxis && /*#__PURE__*/_jsx(YAxis, _extends({
99
100
  axisId: yAxisId
100
101
  }, yAxisVisualProps)), series == null ? void 0 : series.map(_ref4 => {
101
102
  let {
@@ -1,4 +1,4 @@
1
- const _excluded = ["fill", "stroke", "strokeCap", "strokeJoin", "strokeOpacity", "strokeWidth", "gradient", "yAxisId", "d", "animate", "transitions", "transition"];
1
+ const _excluded = ["fill", "stroke", "strokeCap", "strokeJoin", "strokeOpacity", "strokeWidth", "gradient", "xAxisId", "yAxisId", "d", "animate", "transitions", "transition"];
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 { memo } from 'react';
@@ -19,6 +19,7 @@ export const SolidLine = /*#__PURE__*/memo(_ref => {
19
19
  strokeOpacity = 1,
20
20
  strokeWidth = 2,
21
21
  gradient,
22
+ xAxisId,
22
23
  yAxisId,
23
24
  d,
24
25
  animate,
@@ -42,6 +43,7 @@ export const SolidLine = /*#__PURE__*/memo(_ref => {
42
43
  }, props, {
43
44
  children: gradient && /*#__PURE__*/_jsx(Gradient, {
44
45
  gradient: gradient,
46
+ xAxisId: xAxisId,
45
47
  yAxisId: yAxisId
46
48
  })
47
49
  }));
@@ -1703,6 +1703,34 @@ function DataCardWithLineChart() {
1703
1703
  })]
1704
1704
  });
1705
1705
  }
1706
+ function HorizontalLayoutLineChart() {
1707
+ const symbols = ['BTC', 'ETH', 'SOL', 'DOGE', 'ADA'];
1708
+ const allocations = [72, 46, 33, 21, 14];
1709
+ return /*#__PURE__*/_jsx(LineChart, {
1710
+ points: true,
1711
+ showArea: true,
1712
+ showXAxis: true,
1713
+ showYAxis: true,
1714
+ height: 240,
1715
+ layout: "horizontal",
1716
+ series: [{
1717
+ id: 'allocations',
1718
+ data: allocations,
1719
+ color: assets.btc.color
1720
+ }],
1721
+ xAxis: {
1722
+ domain: {
1723
+ min: 0,
1724
+ max: 80
1725
+ },
1726
+ tickLabelFormatter: value => value + "%"
1727
+ },
1728
+ yAxis: {
1729
+ data: symbols,
1730
+ scaleType: 'band'
1731
+ }
1732
+ });
1733
+ }
1706
1734
  function ExampleNavigator() {
1707
1735
  const theme = useTheme();
1708
1736
  const [currentIndex, setCurrentIndex] = useState(0);
@@ -1716,6 +1744,9 @@ function ExampleNavigator() {
1716
1744
  data: [10, 22, 29, 45, 98, 45, 22, 52, 21, 4, 68, 20, 21, 58]
1717
1745
  }]
1718
1746
  })
1747
+ }, {
1748
+ title: 'Horizontal Layout',
1749
+ component: /*#__PURE__*/_jsx(HorizontalLayoutLineChart, {})
1719
1750
  }, {
1720
1751
  title: 'Multiple Lines',
1721
1752
  component: /*#__PURE__*/_jsx(MultipleLine, {})
@@ -16,6 +16,7 @@ export const Point = /*#__PURE__*/memo(_ref => {
16
16
  let {
17
17
  dataX,
18
18
  dataY,
19
+ xAxisId,
19
20
  yAxisId,
20
21
  fill: fillProp,
21
22
  radius = 5,
@@ -41,7 +42,7 @@ export const Point = /*#__PURE__*/memo(_ref => {
41
42
  drawingArea
42
43
  } = useCartesianChartContext();
43
44
  const animate = animateProp != null ? animateProp : animationEnabled;
44
- const xScale = getXScale();
45
+ const xScale = getXScale(xAxisId);
45
46
  const yScale = getYScale(yAxisId);
46
47
  const shouldAnimate = animate != null ? animate : false;
47
48
  const updateTransition = useMemo(() => getTransition((transitions == null ? void 0 : transitions.update) !== undefined ? transitions.update : transition, animate, defaultTransition), [animate, transitions == null ? void 0 : transitions.update, transition]);