@coinbase/cds-web-visualization 3.4.0-beta.18 → 3.4.0-beta.19

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 (68) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dts/chart/Path.d.ts +49 -12
  3. package/dts/chart/Path.d.ts.map +1 -1
  4. package/dts/chart/area/Area.d.ts +6 -11
  5. package/dts/chart/area/Area.d.ts.map +1 -1
  6. package/dts/chart/area/AreaChart.d.ts +15 -2
  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/Bar.d.ts +32 -1
  12. package/dts/chart/bar/Bar.d.ts.map +1 -1
  13. package/dts/chart/bar/BarChart.d.ts +1 -0
  14. package/dts/chart/bar/BarChart.d.ts.map +1 -1
  15. package/dts/chart/bar/BarPlot.d.ts +2 -1
  16. package/dts/chart/bar/BarPlot.d.ts.map +1 -1
  17. package/dts/chart/bar/BarStack.d.ts +4 -10
  18. package/dts/chart/bar/BarStack.d.ts.map +1 -1
  19. package/dts/chart/bar/BarStackGroup.d.ts +1 -0
  20. package/dts/chart/bar/BarStackGroup.d.ts.map +1 -1
  21. package/dts/chart/bar/DefaultBar.d.ts.map +1 -1
  22. package/dts/chart/bar/DefaultBarStack.d.ts.map +1 -1
  23. package/dts/chart/line/DottedLine.d.ts.map +1 -1
  24. package/dts/chart/line/Line.d.ts +17 -20
  25. package/dts/chart/line/Line.d.ts.map +1 -1
  26. package/dts/chart/line/LineChart.d.ts +2 -0
  27. package/dts/chart/line/LineChart.d.ts.map +1 -1
  28. package/dts/chart/line/SolidLine.d.ts.map +1 -1
  29. package/dts/chart/point/Point.d.ts +18 -2
  30. package/dts/chart/point/Point.d.ts.map +1 -1
  31. package/dts/chart/scrubber/DefaultScrubberBeacon.d.ts +22 -29
  32. package/dts/chart/scrubber/DefaultScrubberBeacon.d.ts.map +1 -1
  33. package/dts/chart/scrubber/DefaultScrubberBeaconLabel.d.ts.map +1 -1
  34. package/dts/chart/scrubber/Scrubber.d.ts +85 -52
  35. package/dts/chart/scrubber/Scrubber.d.ts.map +1 -1
  36. package/dts/chart/scrubber/ScrubberBeaconLabelGroup.d.ts +9 -1
  37. package/dts/chart/scrubber/ScrubberBeaconLabelGroup.d.ts.map +1 -1
  38. package/dts/chart/utils/bar.d.ts +34 -0
  39. package/dts/chart/utils/bar.d.ts.map +1 -1
  40. package/dts/chart/utils/path.d.ts +6 -0
  41. package/dts/chart/utils/path.d.ts.map +1 -1
  42. package/dts/chart/utils/transition.d.ts +50 -14
  43. package/dts/chart/utils/transition.d.ts.map +1 -1
  44. package/esm/chart/Path.js +20 -21
  45. package/esm/chart/area/Area.js +2 -0
  46. package/esm/chart/area/AreaChart.js +4 -1
  47. package/esm/chart/area/DottedArea.js +8 -4
  48. package/esm/chart/area/GradientArea.js +6 -3
  49. package/esm/chart/area/SolidArea.js +6 -3
  50. package/esm/chart/bar/Bar.js +2 -0
  51. package/esm/chart/bar/BarChart.js +4 -2
  52. package/esm/chart/bar/BarPlot.js +2 -0
  53. package/esm/chart/bar/BarStack.js +3 -0
  54. package/esm/chart/bar/DefaultBar.js +20 -23
  55. package/esm/chart/bar/DefaultBarStack.js +23 -17
  56. package/esm/chart/line/DottedLine.js +5 -2
  57. package/esm/chart/line/Line.js +12 -26
  58. package/esm/chart/line/LineChart.js +4 -2
  59. package/esm/chart/line/SolidLine.js +6 -3
  60. package/esm/chart/point/Point.js +39 -23
  61. package/esm/chart/scrubber/DefaultScrubberBeacon.js +25 -34
  62. package/esm/chart/scrubber/DefaultScrubberBeaconLabel.js +25 -14
  63. package/esm/chart/scrubber/Scrubber.js +7 -13
  64. package/esm/chart/scrubber/ScrubberBeaconLabelGroup.js +19 -5
  65. package/esm/chart/utils/bar.js +48 -0
  66. package/esm/chart/utils/path.js +9 -0
  67. package/esm/chart/utils/transition.js +63 -41
  68. package/package.json +5 -5
@@ -1,4 +1,4 @@
1
- const _excluded = ["dataX", "dataY", "yAxisId", "fill", "radius", "opacity", "onClick", "className", "style", "classNames", "styles", "stroke", "strokeWidth", "accessibilityLabel", "label", "LabelComponent", "labelPosition", "labelOffset", "labelFont", "testID", "animate", "transition"];
1
+ const _excluded = ["dataX", "dataY", "yAxisId", "fill", "radius", "opacity", "onClick", "className", "style", "classNames", "styles", "stroke", "strokeWidth", "accessibilityLabel", "label", "LabelComponent", "labelPosition", "labelOffset", "labelFont", "testID", "animate", "transitions", "transition"];
2
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
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
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; }
@@ -10,7 +10,7 @@ import React, { memo, useMemo } from 'react';
10
10
  import { cx } from '@coinbase/cds-web';
11
11
  import { m as motion } from 'framer-motion';
12
12
  import { useCartesianChartContext } from '../ChartProvider';
13
- import { projectPoint } from '../utils';
13
+ import { defaultAccessoryEnterTransition, defaultTransition, getTransition, projectPoint } from '../utils';
14
14
  import { DefaultPointLabel } from './DefaultPointLabel';
15
15
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
16
16
  const containerCss = "cds-containerCss-ckemp0e";
@@ -43,6 +43,7 @@ export const Point = /*#__PURE__*/memo(_ref => {
43
43
  labelFont,
44
44
  testID,
45
45
  animate: animateProp,
46
+ transitions,
46
47
  transition
47
48
  } = _ref,
48
49
  svgProps = _objectWithoutProperties(_ref, _excluded);
@@ -53,6 +54,8 @@ export const Point = /*#__PURE__*/memo(_ref => {
53
54
  drawingArea
54
55
  } = useCartesianChartContext();
55
56
  const animate = animateProp !== null && animateProp !== void 0 ? animateProp : animationEnabled;
57
+ const enterTransition = useMemo(() => getTransition(transitions === null || transitions === void 0 ? void 0 : transitions.enter, animate, defaultAccessoryEnterTransition), [animate, transitions === null || transitions === void 0 ? void 0 : transitions.enter]);
58
+ const updateTransition = useMemo(() => getTransition((transitions === null || transitions === void 0 ? void 0 : transitions.update) !== undefined ? transitions.update : transition, animate, defaultTransition), [animate, transitions === null || transitions === void 0 ? void 0 : transitions.update, transition]);
56
59
  const xScale = getXScale();
57
60
  const yScale = getYScale(yAxisId);
58
61
  const pixelCoordinate = useMemo(() => {
@@ -133,7 +136,6 @@ export const Point = /*#__PURE__*/memo(_ref => {
133
136
  cx: pixelCoordinate.x,
134
137
  cy: pixelCoordinate.y,
135
138
  fill: fill,
136
- initial: false,
137
139
  onClick: onClick ? event => onClick(event, {
138
140
  dataX,
139
141
  dataY,
@@ -147,34 +149,48 @@ export const Point = /*#__PURE__*/memo(_ref => {
147
149
  strokeWidth: strokeWidth,
148
150
  style: mergedStyles,
149
151
  tabIndex: onClick ? 0 : -1,
150
- transition: transition,
152
+ transition: {
153
+ cx: updateTransition,
154
+ cy: updateTransition
155
+ },
151
156
  variants: variants,
152
157
  whileHover: onClick ? 'hovered' : 'default',
153
158
  whileTap: onClick ? 'pressed' : 'default'
154
159
  }, svgProps));
155
- }, [style, styles === null || styles === void 0 ? void 0 : styles.point, classNames === null || classNames === void 0 ? void 0 : classNames.point, fill, animate, radius, className, onClick, stroke, strokeWidth, svgProps, dataX, dataY, pixelCoordinate.x, pixelCoordinate.y, accessibilityLabel, transition]);
160
+ }, [style, styles === null || styles === void 0 ? void 0 : styles.point, classNames === null || classNames === void 0 ? void 0 : classNames.point, fill, animate, radius, className, onClick, stroke, strokeWidth, svgProps, dataX, dataY, pixelCoordinate.x, pixelCoordinate.y, accessibilityLabel, updateTransition]);
156
161
  if (!xScale || !yScale) {
157
162
  return;
158
163
  }
159
- return /*#__PURE__*/_jsxs("g", {
164
+ return /*#__PURE__*/_jsx("g", {
160
165
  opacity: isWithinDrawingArea ? 1 : 0,
161
- children: [/*#__PURE__*/_jsx("g", {
162
- className: cx(containerCss, classNames === null || classNames === void 0 ? void 0 : classNames.root),
163
- "data-testid": testID,
164
- opacity: opacity,
165
- style: styles === null || styles === void 0 ? void 0 : styles.root,
166
- children: innerPoint
167
- }), label && /*#__PURE__*/_jsx(LabelComponent, {
168
- dataX: dataX,
169
- dataY: dataY,
170
- fill: fill,
171
- font: labelFont,
172
- offset: labelOffset,
173
- position: labelPosition,
174
- x: pixelCoordinate.x,
175
- y: pixelCoordinate.y,
176
- children: label
177
- })]
166
+ children: /*#__PURE__*/_jsxs(motion.g, {
167
+ animate: {
168
+ opacity: 1
169
+ },
170
+ initial: animate ? {
171
+ opacity: 0
172
+ } : false,
173
+ transition: {
174
+ opacity: enterTransition
175
+ },
176
+ children: [/*#__PURE__*/_jsx("g", {
177
+ className: cx(containerCss, classNames === null || classNames === void 0 ? void 0 : classNames.root),
178
+ "data-testid": testID,
179
+ opacity: opacity,
180
+ style: styles === null || styles === void 0 ? void 0 : styles.root,
181
+ children: innerPoint
182
+ }), label && /*#__PURE__*/_jsx(LabelComponent, {
183
+ dataX: dataX,
184
+ dataY: dataY,
185
+ fill: fill,
186
+ font: labelFont,
187
+ offset: labelOffset,
188
+ position: labelPosition,
189
+ x: pixelCoordinate.x,
190
+ y: pixelCoordinate.y,
191
+ children: label
192
+ })]
193
+ })
178
194
  });
179
195
  });
180
196
  import "./Point.css";
@@ -4,9 +4,10 @@ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object
4
4
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
5
5
  function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
6
6
  import { forwardRef, memo, useImperativeHandle, useMemo } from 'react';
7
+ import { usePreviousValue } from '@coinbase/cds-common/hooks/usePreviousValue';
7
8
  import { m as motion, useAnimate } from 'framer-motion';
8
9
  import { useCartesianChartContext } from '../ChartProvider';
9
- import { defaultTransition, projectPoint } from '../utils';
10
+ import { defaultTransition, getTransition, instantTransition, projectPoint } from '../utils';
10
11
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
12
  const defaultRadius = 5;
12
13
  const defaultStrokeWidth = 2;
@@ -54,10 +55,13 @@ export const DefaultScrubberBeacon = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((
54
55
  var _ref2;
55
56
  return (_ref2 = colorProp !== null && colorProp !== void 0 ? colorProp : targetSeries === null || targetSeries === void 0 ? void 0 : targetSeries.color) !== null && _ref2 !== void 0 ? _ref2 : 'var(--color-fgPrimary)';
56
57
  }, [colorProp, targetSeries]);
58
+ const prevIsIdle = usePreviousValue(isIdle);
59
+ const isIdleTransition = prevIsIdle !== undefined && isIdle !== prevIsIdle;
57
60
  const updateTransition = useMemo(() => {
58
- var _transitions$update;
59
- return (_transitions$update = transitions === null || transitions === void 0 ? void 0 : transitions.update) !== null && _transitions$update !== void 0 ? _transitions$update : defaultTransition;
60
- }, [transitions === null || transitions === void 0 ? void 0 : transitions.update]);
61
+ if (isIdleTransition) return instantTransition;
62
+ if (!isIdle) return instantTransition;
63
+ return getTransition(transitions === null || transitions === void 0 ? void 0 : transitions.update, animate, defaultTransition);
64
+ }, [transitions === null || transitions === void 0 ? void 0 : transitions.update, isIdle, animate, isIdleTransition]);
61
65
  const pulseTransition = useMemo(() => {
62
66
  var _transitions$pulse;
63
67
  return (_transitions$pulse = transitions === null || transitions === void 0 ? void 0 : transitions.pulse) !== null && _transitions$pulse !== void 0 ? _transitions$pulse : defaultPulseTransition;
@@ -119,35 +123,10 @@ export const DefaultScrubberBeacon = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((
119
123
  r: pulseRadiusStart
120
124
  }
121
125
  });
122
- const beaconCircle = isIdle && animate ? /*#__PURE__*/_jsx(motion.circle, {
123
- animate: {
124
- cx: pixelCoordinate.x,
125
- cy: pixelCoordinate.y
126
- },
127
- className: className,
128
- cx: pixelCoordinate.x,
129
- cy: pixelCoordinate.y,
130
- fill: color,
131
- initial: false,
132
- r: radius,
133
- stroke: stroke,
134
- strokeWidth: strokeWidth,
135
- style: style,
136
- transition: updateTransition
137
- }) : /*#__PURE__*/_jsx("circle", {
138
- className: className,
139
- cx: pixelCoordinate.x,
140
- cy: pixelCoordinate.y,
141
- fill: color,
142
- r: radius,
143
- stroke: stroke,
144
- strokeWidth: strokeWidth,
145
- style: style
146
- });
147
126
  return /*#__PURE__*/_jsxs("g", {
148
127
  "data-testid": testID,
149
128
  opacity: isWithinDrawingArea ? opacity : 0,
150
- children: [isIdle && (animate ? /*#__PURE__*/_jsx(motion.g, {
129
+ children: [isIdle && /*#__PURE__*/_jsx(motion.g, {
151
130
  animate: {
152
131
  x: pixelCoordinate.x,
153
132
  y: pixelCoordinate.y
@@ -155,9 +134,21 @@ export const DefaultScrubberBeacon = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((
155
134
  initial: false,
156
135
  transition: updateTransition,
157
136
  children: pulseCircle
158
- }) : /*#__PURE__*/_jsx("g", {
159
- transform: "translate(".concat(pixelCoordinate.x, ", ").concat(pixelCoordinate.y, ")"),
160
- children: pulseCircle
161
- })), beaconCircle]
137
+ }), /*#__PURE__*/_jsx(motion.circle, {
138
+ animate: {
139
+ cx: pixelCoordinate.x,
140
+ cy: pixelCoordinate.y
141
+ },
142
+ className: className,
143
+ cx: pixelCoordinate.x,
144
+ cy: pixelCoordinate.y,
145
+ fill: color,
146
+ initial: false,
147
+ r: radius,
148
+ stroke: stroke,
149
+ strokeWidth: strokeWidth,
150
+ style: style,
151
+ transition: updateTransition
152
+ })]
162
153
  });
163
154
  }));
@@ -1,4 +1,4 @@
1
- const _excluded = ["background", "color", "elevated", "borderRadius", "font", "verticalAlignment", "inset", "label"];
1
+ const _excluded = ["background", "color", "elevated", "borderRadius", "font", "verticalAlignment", "inset", "label", "transition", "y"];
2
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
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
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; }
@@ -7,6 +7,7 @@ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e =
7
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
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
9
  import { memo } from 'react';
10
+ import { m as motion } from 'framer-motion';
10
11
  import { ChartText } from '../text';
11
12
  import { jsx as _jsx } from "react/jsx-runtime";
12
13
  const labelVerticalInset = 3.5;
@@ -28,19 +29,29 @@ export const DefaultScrubberBeaconLabel = /*#__PURE__*/memo(_ref => {
28
29
  top: labelVerticalInset,
29
30
  bottom: labelVerticalInset
30
31
  },
31
- label
32
+ label,
33
+ transition,
34
+ y
32
35
  } = _ref,
33
36
  chartTextProps = _objectWithoutProperties(_ref, _excluded);
34
- return /*#__PURE__*/_jsx(ChartText, _objectSpread(_objectSpread({
35
- disableRepositioning: true,
36
- background: background,
37
- borderRadius: borderRadius,
38
- color: color,
39
- elevated: elevated,
40
- font: font,
41
- inset: inset,
42
- verticalAlignment: verticalAlignment
43
- }, chartTextProps), {}, {
44
- children: label
45
- }));
37
+ return /*#__PURE__*/_jsx(motion.g, {
38
+ animate: {
39
+ y
40
+ },
41
+ initial: false,
42
+ transition: transition,
43
+ children: /*#__PURE__*/_jsx(ChartText, _objectSpread(_objectSpread({
44
+ disableRepositioning: true,
45
+ background: background,
46
+ borderRadius: borderRadius,
47
+ color: color,
48
+ elevated: elevated,
49
+ font: font,
50
+ inset: inset,
51
+ verticalAlignment: verticalAlignment,
52
+ y: transition ? 0 : y
53
+ }, chartTextProps), {}, {
54
+ children: label
55
+ }))
56
+ });
46
57
  });
@@ -7,7 +7,7 @@ import React, { forwardRef, memo, useImperativeHandle, useMemo } from 'react';
7
7
  import { m as motion } from 'framer-motion';
8
8
  import { useCartesianChartContext } from '../ChartProvider';
9
9
  import { ReferenceLine } from '../line';
10
- import { accessoryFadeTransitionDelay, accessoryFadeTransitionDuration, getPointOnScale, useScrubberContext } from '../utils';
10
+ import { defaultAccessoryEnterTransition, getPointOnScale, getTransition, useScrubberContext } from '../utils';
11
11
  import { DefaultScrubberBeacon } from './DefaultScrubberBeacon';
12
12
  import { DefaultScrubberLabel } from './DefaultScrubberLabel';
13
13
  import { ScrubberBeaconGroup } from './ScrubberBeaconGroup';
@@ -40,6 +40,7 @@ export const Scrubber = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) =>
40
40
  testID,
41
41
  idlePulse,
42
42
  beaconTransitions,
43
+ transitions = beaconTransitions,
43
44
  beaconStroke,
44
45
  styles,
45
46
  classNames
@@ -118,6 +119,7 @@ export const Scrubber = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) =>
118
119
  color: s.color
119
120
  }))) !== null && _series$filter$filter !== void 0 ? _series$filter$filter : [];
120
121
  }, [series, filteredSeriesIds]);
122
+ const groupEnterTransition = useMemo(() => getTransition(transitions === null || transitions === void 0 ? void 0 : transitions.enter, animate, defaultAccessoryEnterTransition), [transitions === null || transitions === void 0 ? void 0 : transitions.enter, animate]);
121
123
 
122
124
  // Check if we have at least the default X scale
123
125
  const defaultXScale = getXScale();
@@ -133,16 +135,7 @@ export const Scrubber = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) =>
133
135
  }, animate ? {
134
136
  animate: {
135
137
  opacity: 1,
136
- transition: {
137
- duration: accessoryFadeTransitionDuration,
138
- delay: accessoryFadeTransitionDelay
139
- }
140
- },
141
- exit: {
142
- opacity: 0,
143
- transition: {
144
- duration: accessoryFadeTransitionDuration
145
- }
138
+ transition: groupEnterTransition
146
139
  },
147
140
  initial: {
148
141
  opacity: 0
@@ -181,14 +174,15 @@ export const Scrubber = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) =>
181
174
  stroke: beaconStroke,
182
175
  style: styles === null || styles === void 0 ? void 0 : styles.beacon,
183
176
  testID: testID,
184
- transitions: beaconTransitions
177
+ transitions: transitions
185
178
  }), !hideBeaconLabels && beaconLabels.length > 0 && /*#__PURE__*/_jsx(ScrubberBeaconLabelGroup, {
186
179
  BeaconLabelComponent: BeaconLabelComponent,
187
180
  labelFont: beaconLabelFont,
188
181
  labelHorizontalOffset: beaconLabelHorizontalOffset,
189
182
  labelMinGap: beaconLabelMinGap,
190
183
  labelPreferredSide: beaconLabelPreferredSide,
191
- labels: beaconLabels
184
+ labels: beaconLabels,
185
+ transitions: transitions
192
186
  })]
193
187
  }));
194
188
  }));
@@ -4,8 +4,9 @@ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object
4
4
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
5
5
  function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
6
6
  import { memo, useCallback, useMemo, useState } from 'react';
7
+ import { usePreviousValue } from '@coinbase/cds-common/hooks/usePreviousValue';
7
8
  import { useCartesianChartContext } from '../ChartProvider';
8
- import { getPointOnScale, useScrubberContext } from '../utils';
9
+ import { defaultTransition, getPointOnScale, getTransition, instantTransition, useScrubberContext } from '../utils';
9
10
  import { calculateLabelYPositions, getLabelPosition } from '../utils/scrubber';
10
11
  import { DefaultScrubberBeaconLabel } from './DefaultScrubberBeaconLabel';
11
12
  import { jsx as _jsx } from "react/jsx-runtime";
@@ -20,7 +21,8 @@ const PositionedLabel = /*#__PURE__*/memo(_ref => {
20
21
  onDimensionsChange,
21
22
  BeaconLabelComponent,
22
23
  labelHorizontalOffset,
23
- labelFont
24
+ labelFont,
25
+ updateTransition
24
26
  } = _ref;
25
27
  const pos = positions[index];
26
28
 
@@ -40,6 +42,7 @@ const PositionedLabel = /*#__PURE__*/memo(_ref => {
40
42
  label: label,
41
43
  onDimensionsChange: d => onDimensionsChange(seriesId, d),
42
44
  seriesId: seriesId,
45
+ transition: updateTransition,
43
46
  x: x,
44
47
  y: y
45
48
  });
@@ -51,7 +54,8 @@ export const ScrubberBeaconLabelGroup = /*#__PURE__*/memo(_ref2 => {
51
54
  labelHorizontalOffset = 16,
52
55
  labelFont,
53
56
  labelPreferredSide = 'right',
54
- BeaconLabelComponent = DefaultScrubberBeaconLabel
57
+ BeaconLabelComponent = DefaultScrubberBeaconLabel,
58
+ transitions
55
59
  } = _ref2;
56
60
  const {
57
61
  getSeries,
@@ -60,11 +64,20 @@ export const ScrubberBeaconLabelGroup = /*#__PURE__*/memo(_ref2 => {
60
64
  getYScale,
61
65
  getXAxis,
62
66
  drawingArea,
63
- dataLength
67
+ dataLength,
68
+ animate
64
69
  } = useCartesianChartContext();
65
70
  const {
66
71
  scrubberPosition
67
72
  } = useScrubberContext();
73
+ const isIdle = scrubberPosition === undefined;
74
+ const prevIsIdle = usePreviousValue(isIdle);
75
+ const isIdleTransition = prevIsIdle !== undefined && isIdle !== prevIsIdle;
76
+ const updateTransition = useMemo(() => {
77
+ if (isIdleTransition) return instantTransition;
78
+ if (!isIdle) return instantTransition;
79
+ return getTransition(transitions === null || transitions === void 0 ? void 0 : transitions.update, animate, defaultTransition);
80
+ }, [transitions === null || transitions === void 0 ? void 0 : transitions.update, isIdle, animate, isIdleTransition]);
68
81
  const [labelDimensions, setLabelDimensions] = useState({});
69
82
  const handleDimensionsChange = useCallback((seriesId, dimensions) => {
70
83
  setLabelDimensions(prev => {
@@ -181,7 +194,8 @@ export const ScrubberBeaconLabelGroup = /*#__PURE__*/memo(_ref2 => {
181
194
  onDimensionsChange: handleDimensionsChange,
182
195
  position: currentPosition,
183
196
  positions: allLabelPositions,
184
- seriesId: info.seriesId
197
+ seriesId: info.seriesId,
198
+ updateTransition: updateTransition
185
199
  }, info.seriesId);
186
200
  });
187
201
  });
@@ -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,6 +1,15 @@
1
1
  import { area as d3Area, curveBumpX, curveCatmullRom, curveLinear, curveLinearClosed, curveMonotoneX, curveNatural, curveStep, curveStepAfter, curveStepBefore, line as d3Line } from 'd3-shape';
2
2
  import { projectPoint, projectPoints } from './point';
3
3
  import { isCategoricalScale } from './scale';
4
+
5
+ /**
6
+ * Default enter transition for path-based components (Line, Area).
7
+ * `{ type: 'tween', duration: 0.5 }`
8
+ */
9
+ export const defaultPathEnterTransition = {
10
+ type: 'tween',
11
+ duration: 0.5
12
+ };
4
13
  /**
5
14
  * Get the d3 curve function for a path.
6
15
  * See https://d3js.org/d3-shape/curve
@@ -5,10 +5,11 @@ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol"
5
5
  function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
6
6
  import { useEffect, useRef } from 'react';
7
7
  import { interpolatePath } from 'd3-interpolate-path';
8
- import { animate, useMotionValue, useTransform } from 'framer-motion';
8
+ import { animate, useMotionValue } from 'framer-motion';
9
9
 
10
10
  /**
11
- * Default transition configuration used across all chart components.
11
+ * Default update transition used across all chart components.
12
+ * `{ type: 'spring', stiffness: 900, damping: 120, mass: 4 }`
12
13
  */
13
14
  export const defaultTransition = {
14
15
  type: 'spring',
@@ -17,6 +18,15 @@ export const defaultTransition = {
17
18
  mass: 4
18
19
  };
19
20
 
21
+ /**
22
+ * Instant transition that completes immediately with no animation.
23
+ * Used when a transition is set to `null`.
24
+ */
25
+ export const instantTransition = {
26
+ type: 'tween',
27
+ duration: 0
28
+ };
29
+
20
30
  /**
21
31
  * Duration in seconds for accessory elements to fade in.
22
32
  */
@@ -27,85 +37,97 @@ export const accessoryFadeTransitionDuration = 0.15;
27
37
  */
28
38
  export const accessoryFadeTransitionDelay = 0.35;
29
39
 
40
+ /**
41
+ * Default enter transition for accessory elements (Point, Scrubber beacons).
42
+ * `{ type: 'tween', duration: 0.15, delay: 0.35 }`
43
+ */
44
+ export const defaultAccessoryEnterTransition = {
45
+ type: 'tween',
46
+ duration: accessoryFadeTransitionDuration,
47
+ delay: accessoryFadeTransitionDelay
48
+ };
49
+
50
+ /**
51
+ * Resolves a transition value based on the animation state and a default.
52
+ * @note Passing in null will disable an animation.
53
+ * @note Passing in undefined will use the provided default.
54
+ */
55
+ export const getTransition = (value, animate, defaultValue) => {
56
+ if (!animate || value === null) return instantTransition;
57
+ return value !== null && value !== void 0 ? value : defaultValue;
58
+ };
59
+
30
60
  /**
31
61
  * Hook for path animation state and transitions.
32
62
  *
33
63
  * @param currentPath - Current target path to animate to
34
64
  * @param initialPath - Initial path for enter animation. When provided, the first animation will go from initialPath to currentPath.
35
- * @param transition - Transition configuration
65
+ * @param transitions - Transition configuration for enter and update animations
36
66
  * @returns MotionValue containing the current interpolated path string
37
67
  *
38
68
  * @example
39
69
  * // Simple path transition
40
70
  * const animatedPath = usePathTransition({
41
71
  * currentPath: d ?? '',
42
- * transition: {
43
- * type: 'spring',
44
- * stiffness: 300,
45
- * damping: 20
46
- * }
72
+ * transitions: {
73
+ * update: { type: 'spring', stiffness: 300, damping: 20 },
74
+ * },
47
75
  * });
48
76
  *
49
77
  * @example
50
- * // Time based animation
78
+ * // Enter animation with different initial config (like DefaultBar)
51
79
  * const animatedPath = usePathTransition({
52
80
  * currentPath: targetPath,
53
81
  * initialPath: baselinePath,
54
- * transition: {
55
- * type: 'tween',
56
- * duration: 0.3,
57
- * ease: 'easeInOut'
58
- * }
82
+ * transitions: {
83
+ * enter: { type: 'tween', duration: 0.5 },
84
+ * update: { type: 'spring', stiffness: 900, damping: 120, mass: 4 },
85
+ * },
59
86
  * });
60
87
  */
61
88
  export const usePathTransition = _ref => {
89
+ var _transitions$update;
62
90
  let {
63
91
  currentPath,
64
92
  initialPath,
93
+ transitions,
65
94
  transition = defaultTransition
66
95
  } = _ref;
67
- const isInitialRender = useRef(true);
96
+ const updateTransition = (_transitions$update = transitions === null || transitions === void 0 ? void 0 : transitions.update) !== null && _transitions$update !== void 0 ? _transitions$update : transition;
97
+ const enterTransition = transitions === null || transitions === void 0 ? void 0 : transitions.enter;
68
98
  const previousPathRef = useRef(initialPath !== null && initialPath !== void 0 ? initialPath : currentPath);
69
- const targetPathRef = useRef(currentPath);
99
+ const targetPathRef = useRef(initialPath !== null && initialPath !== void 0 ? initialPath : currentPath);
70
100
  const animationRef = useRef(null);
71
- const progress = useMotionValue(0);
72
-
73
- // Derive the interpolated path from progress using useTransform
74
- const interpolatedPath = useTransform(progress, latest => {
75
- const pathInterpolator = interpolatePath(previousPathRef.current, targetPathRef.current);
76
- return pathInterpolator(latest);
77
- });
101
+ const isFirstAnimation = useRef(!!initialPath);
102
+ const animatedPath = useMotionValue(initialPath !== null && initialPath !== void 0 ? initialPath : currentPath);
78
103
  useEffect(() => {
79
- // Only proceed if the target path has actually changed
80
104
  if (targetPathRef.current !== currentPath) {
81
- // Cancel any ongoing animation before starting a new one
82
- const wasAnimating = !!animationRef.current;
105
+ const currentVisualPath = animatedPath.get();
83
106
  if (animationRef.current) {
84
- animationRef.current.cancel();
107
+ animationRef.current.stop();
85
108
  animationRef.current = null;
86
- }
87
- const currentInterpolatedPath = interpolatedPath.get();
88
-
89
- // If we were animating and the interpolated path is different from both start and end,
90
- // use it as the starting point for the next animation (smooth interruption)
91
- const isInterpolatedPosition = currentInterpolatedPath !== previousPathRef.current && currentInterpolatedPath !== currentPath;
92
- if (wasAnimating && isInterpolatedPosition) {
93
- previousPathRef.current = currentInterpolatedPath;
109
+ previousPathRef.current = currentVisualPath;
94
110
  }
95
111
  targetPathRef.current = currentPath;
96
- progress.set(0);
97
- animationRef.current = animate(progress, 1, _objectSpread(_objectSpread({}, transition), {}, {
112
+ const activeTransition = isFirstAnimation.current && enterTransition !== undefined ? enterTransition : updateTransition;
113
+ isFirstAnimation.current = false;
114
+ const pathInterpolator = interpolatePath(previousPathRef.current, currentPath);
115
+ animationRef.current = animate(0, 1, _objectSpread(_objectSpread({}, activeTransition), {}, {
116
+ onUpdate: latest => {
117
+ animatedPath.set(pathInterpolator(latest));
118
+ },
98
119
  onComplete: () => {
120
+ animatedPath.set(currentPath);
99
121
  previousPathRef.current = currentPath;
122
+ animationRef.current = null;
100
123
  }
101
124
  }));
102
- isInitialRender.current = false;
103
125
  }
104
126
  return () => {
105
127
  if (animationRef.current) {
106
- animationRef.current.cancel();
128
+ animationRef.current.stop();
107
129
  }
108
130
  };
109
- }, [currentPath, transition, progress, interpolatedPath]);
110
- return interpolatedPath;
131
+ }, [currentPath, updateTransition, enterTransition, animatedPath]);
132
+ return animatedPath;
111
133
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coinbase/cds-web-visualization",
3
- "version": "3.4.0-beta.18",
3
+ "version": "3.4.0-beta.19",
4
4
  "description": "Coinbase Design System - Web Sparkline",
5
5
  "repository": {
6
6
  "type": "git",
@@ -38,10 +38,10 @@
38
38
  "CHANGELOG"
39
39
  ],
40
40
  "peerDependencies": {
41
- "@coinbase/cds-common": "^8.43.0",
41
+ "@coinbase/cds-common": "^8.48.0",
42
42
  "@coinbase/cds-lottie-files": "^3.3.4",
43
43
  "@coinbase/cds-utils": "^2.3.5",
44
- "@coinbase/cds-web": "^8.43.0",
44
+ "@coinbase/cds-web": "^8.48.0",
45
45
  "react": "^18.3.1",
46
46
  "react-dom": "^18.3.1"
47
47
  },
@@ -58,10 +58,10 @@
58
58
  "@babel/preset-env": "^7.28.0",
59
59
  "@babel/preset-react": "^7.27.1",
60
60
  "@babel/preset-typescript": "^7.27.1",
61
- "@coinbase/cds-common": "^8.43.0",
61
+ "@coinbase/cds-common": "^8.48.0",
62
62
  "@coinbase/cds-lottie-files": "^3.3.4",
63
63
  "@coinbase/cds-utils": "^2.3.5",
64
- "@coinbase/cds-web": "^8.43.0",
64
+ "@coinbase/cds-web": "^8.48.0",
65
65
  "@linaria/core": "^3.0.0-beta.22",
66
66
  "@types/react": "^18.3.12",
67
67
  "@types/react-dom": "^18.3.1"