@coinbase/cds-mobile-visualization 3.4.0-beta.24 → 3.4.0-beta.25

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 (43) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dts/chart/Path.d.ts +2 -1
  3. package/dts/chart/Path.d.ts.map +1 -1
  4. package/dts/chart/bar/Bar.d.ts +18 -54
  5. package/dts/chart/bar/Bar.d.ts.map +1 -1
  6. package/dts/chart/bar/BarChart.d.ts +2 -2
  7. package/dts/chart/bar/BarPlot.d.ts.map +1 -1
  8. package/dts/chart/bar/BarStack.d.ts +4 -4
  9. package/dts/chart/bar/BarStack.d.ts.map +1 -1
  10. package/dts/chart/bar/DefaultBar.d.ts.map +1 -1
  11. package/dts/chart/bar/DefaultBarStack.d.ts.map +1 -1
  12. package/dts/chart/point/Point.d.ts +2 -1
  13. package/dts/chart/point/Point.d.ts.map +1 -1
  14. package/dts/chart/scrubber/Scrubber.d.ts +4 -2
  15. package/dts/chart/scrubber/Scrubber.d.ts.map +1 -1
  16. package/dts/chart/utils/bar.d.ts +155 -0
  17. package/dts/chart/utils/bar.d.ts.map +1 -1
  18. package/dts/chart/utils/chart.d.ts +2 -1
  19. package/dts/chart/utils/chart.d.ts.map +1 -1
  20. package/dts/chart/utils/path.d.ts.map +1 -1
  21. package/dts/sparkline/Sparkline.d.ts +2 -1
  22. package/dts/sparkline/Sparkline.d.ts.map +1 -1
  23. package/dts/sparkline/SparklineArea.d.ts +2 -1
  24. package/dts/sparkline/SparklineArea.d.ts.map +1 -1
  25. package/dts/sparkline/SparklineGradient.d.ts +2 -1
  26. package/dts/sparkline/SparklineGradient.d.ts.map +1 -1
  27. package/dts/sparkline/sparkline-interactive/SparklineInteractive.d.ts +2 -1
  28. package/dts/sparkline/sparkline-interactive/SparklineInteractive.d.ts.map +1 -1
  29. package/esm/chart/bar/Bar.js +8 -14
  30. package/esm/chart/bar/BarChart.js +7 -7
  31. package/esm/chart/bar/BarPlot.js +37 -46
  32. package/esm/chart/bar/BarStack.js +71 -604
  33. package/esm/chart/bar/DefaultBar.js +11 -18
  34. package/esm/chart/bar/DefaultBarStack.js +12 -21
  35. package/esm/chart/bar/__stories__/BarChart.stories.js +104 -6
  36. package/esm/chart/utils/bar.js +775 -0
  37. package/esm/chart/utils/chart.js +2 -1
  38. package/esm/chart/utils/path.js +5 -12
  39. package/esm/sparkline/Sparkline.js +2 -1
  40. package/esm/sparkline/SparklineArea.js +2 -1
  41. package/esm/sparkline/SparklineGradient.js +2 -1
  42. package/esm/sparkline/sparkline-interactive/SparklineInteractive.js +2 -1
  43. package/package.json +5 -5
@@ -44,9 +44,9 @@ export const BarChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) =>
44
44
  });
45
45
  }, [seriesProp, stacked]);
46
46
  const seriesIds = useMemo(() => series == null ? void 0 : series.map(s => s.id), [series]);
47
- const isHorizontal = chartProps.layout === 'horizontal';
48
- const defaultXScaleType = isHorizontal ? 'linear' : 'band';
49
- const defaultYScaleType = isHorizontal ? 'band' : 'linear';
47
+ const isHorizontalLayout = chartProps.layout === 'horizontal';
48
+ const defaultXScaleType = isHorizontalLayout ? 'linear' : 'band';
49
+ const defaultYScaleType = isHorizontalLayout ? 'band' : 'linear';
50
50
 
51
51
  // Split axis props into config props for Chart and visual props for axis components
52
52
  const _ref2 = xAxis || {},
@@ -82,24 +82,24 @@ export const BarChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) =>
82
82
  scaleType: xScaleType != null ? xScaleType : defaultXScaleType,
83
83
  data: xData,
84
84
  categoryPadding: xCategoryPadding,
85
- domain: isHorizontal && !hasNegativeValues ? _extends({
85
+ domain: isHorizontalLayout && !hasNegativeValues ? _extends({
86
86
  min: 0
87
87
  }, xDomain) : xDomain,
88
88
  domainLimit: xDomainLimit,
89
89
  range: xRange
90
- }), [xScaleType, defaultXScaleType, xData, xCategoryPadding, isHorizontal, hasNegativeValues, xDomain, xDomainLimit, xRange]);
90
+ }), [xScaleType, defaultXScaleType, xData, xCategoryPadding, isHorizontalLayout, hasNegativeValues, xDomain, xDomainLimit, xRange]);
91
91
 
92
92
  // Set default min domain to 0 for bar chart, but only if there are no negative values.
93
93
  const yAxisConfig = useMemo(() => ({
94
94
  scaleType: yScaleType != null ? yScaleType : defaultYScaleType,
95
95
  data: yData,
96
96
  categoryPadding: yCategoryPadding,
97
- domain: !isHorizontal && !hasNegativeValues ? _extends({
97
+ domain: !isHorizontalLayout && !hasNegativeValues ? _extends({
98
98
  min: 0
99
99
  }, yDomain) : yDomain,
100
100
  domainLimit: yDomainLimit,
101
101
  range: yRange
102
- }), [yScaleType, defaultYScaleType, yData, yCategoryPadding, isHorizontal, hasNegativeValues, yDomain, yDomainLimit, yRange]);
102
+ }), [yScaleType, defaultYScaleType, yData, yCategoryPadding, isHorizontalLayout, hasNegativeValues, yDomain, yDomainLimit, yRange]);
103
103
  return /*#__PURE__*/_jsxs(CartesianChart, _extends({}, chartProps, {
104
104
  ref: ref,
105
105
  inset: inset,
@@ -1,9 +1,17 @@
1
- import { memo, useMemo } from 'react';
2
- import { Group, Skia } from '@shopify/react-native-skia';
1
+ import { memo, useEffect, useMemo, useState } from 'react';
2
+ import { useSharedValue } from 'react-native-reanimated';
3
+ import { Group, Skia, usePathInterpolation } from '@shopify/react-native-skia';
3
4
  import { useCartesianChartContext } from '../ChartProvider';
4
- import { defaultAxisId } from '../utils';
5
+ import { getStackGroups } from '../utils';
6
+ import { buildTransition, instantTransition } from '../utils/transition';
5
7
  import { BarStackGroup } from './BarStackGroup';
6
8
  import { jsx as _jsx } from "react/jsx-runtime";
9
+ const makeClipPath = area => {
10
+ const path = Skia.Path.Make();
11
+ path.addRect(area);
12
+ return path;
13
+ };
14
+
7
15
  /**
8
16
  * BarPlot component that handles multiple series with proper stacking coordination.
9
17
  * Groups series by stack ID + y-axis ID combination and renders BarStackGroup for each group.
@@ -28,6 +36,7 @@ export const BarPlot = /*#__PURE__*/memo(_ref => {
28
36
  transition
29
37
  } = _ref;
30
38
  const {
39
+ animate,
31
40
  series: allSeries,
32
41
  drawingArea
33
42
  } = useCartesianChartContext();
@@ -38,50 +47,32 @@ export const BarPlot = /*#__PURE__*/memo(_ref => {
38
47
  }
39
48
  return allSeries;
40
49
  }, [allSeries, seriesIds]);
41
- const stackGroups = useMemo(() => {
42
- const groups = new Map();
43
-
44
- // Group series into stacks based on stackId + axis ID combination
45
- targetSeries.forEach(series => {
46
- var _series$xAxisId, _series$yAxisId;
47
- const xAxisId = (_series$xAxisId = series.xAxisId) != null ? _series$xAxisId : defaultAxisId;
48
- const yAxisId = (_series$yAxisId = series.yAxisId) != null ? _series$yAxisId : defaultAxisId;
49
- const stackId = series.stackId || "individual-" + series.id;
50
- const stackKey = stackId + ":" + xAxisId + ":" + yAxisId;
51
- if (!groups.has(stackKey)) {
52
- groups.set(stackKey, {
53
- stackId: stackKey,
54
- series: [],
55
- xAxisId: series.xAxisId,
56
- yAxisId: series.yAxisId
57
- });
58
- }
59
- const group = groups.get(stackKey);
60
- group.series.push(series);
61
- });
62
- return Array.from(groups.values());
63
- }, [targetSeries]);
64
-
65
- // Create clip path for the entire chart area (shared by all bars)
66
- const clipPath = useMemo(() => {
67
- if (!drawingArea) return null;
68
- const clip = Skia.Path.Make();
69
- clip.addRect({
70
- x: drawingArea.x,
71
- y: drawingArea.y,
72
- width: drawingArea.width,
73
- height: drawingArea.height
74
- });
75
- return clip;
76
- }, [drawingArea]);
77
- if (!clipPath) {
78
- return null;
79
- }
80
-
81
- // Note: Clipping is now handled here at the BarPlot level (one clip path for all bars!)
82
- // This is much more efficient than creating a clip path for each individual bar
50
+ const stackGroups = useMemo(() => getStackGroups(targetSeries), [targetSeries]);
51
+ const clipUpdateTransition = useMemo(() => (transitions == null ? void 0 : transitions.update) !== undefined ? transitions.update : instantTransition, [transitions == null ? void 0 : transitions.update]);
52
+ const emptyPath = useMemo(() => Skia.Path.Make(), []);
53
+ const initialPath = useMemo(() => drawingArea ? makeClipPath(drawingArea) : emptyPath,
54
+ // eslint-disable-next-line react-hooks/exhaustive-deps
55
+ []);
56
+ const [clipPaths, setClipPaths] = useState({
57
+ from: initialPath,
58
+ to: initialPath
59
+ });
60
+ const clipProgress = useSharedValue(0);
61
+ useEffect(() => {
62
+ if (!drawingArea) return;
63
+ const nextPath = makeClipPath(drawingArea);
64
+ setClipPaths(prev => ({
65
+ from: prev.to,
66
+ to: nextPath
67
+ }));
68
+ clipProgress.value = 0;
69
+ clipProgress.value = buildTransition(1, animate ? clipUpdateTransition : null);
70
+ // eslint-disable-next-line react-hooks/exhaustive-deps
71
+ }, [drawingArea, animate, clipUpdateTransition]);
72
+ const animatedClipPath = usePathInterpolation(clipProgress, [0, 1], [clipPaths.from, clipPaths.to]);
73
+ if (!drawingArea) return;
83
74
  return /*#__PURE__*/_jsx(Group, {
84
- clip: clipPath,
75
+ clip: animatedClipPath,
85
76
  children: stackGroups.map((group, stackIndex) => /*#__PURE__*/_jsx(BarStackGroup, {
86
77
  BarComponent: defaultBarComponent,
87
78
  BarStackComponent: BarStackComponent,