@coinbase/cds-mcp-server 8.27.1 → 8.27.3

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.
package/CHANGELOG.md CHANGED
@@ -8,6 +8,14 @@ All notable changes to this project will be documented in this file.
8
8
 
9
9
  <!-- template-start -->
10
10
 
11
+ ## 8.27.3 ((12/5/2025, 01:46 PM PST))
12
+
13
+ This is an artificial version bump with no new change.
14
+
15
+ ## 8.27.2 ((12/4/2025, 04:23 PM PST))
16
+
17
+ This is an artificial version bump with no new change.
18
+
11
19
  ## 8.27.1 ((12/4/2025, 06:51 AM PST))
12
20
 
13
21
  This is an artificial version bump with no new change.
@@ -1600,7 +1600,7 @@ function MonotoneAssetPrice() {
1600
1600
  );
1601
1601
 
1602
1602
  const CustomScrubberBeacon = memo(
1603
- ({ dataX, dataY, seriesId, isIdle, animate = true }: ScrubberBeaconProps) => {
1603
+ forwardRef(({ dataX, dataY, seriesId, isIdle, animate = true }: ScrubberBeaconProps, ref) => {
1604
1604
  const { getSeries, getXSerializableScale, getYSerializableScale } =
1605
1605
  useCartesianChartContext();
1606
1606
 
@@ -1614,6 +1614,9 @@ function MonotoneAssetPrice() {
1614
1614
  const animatedX = useSharedValue(0);
1615
1615
  const animatedY = useSharedValue(0);
1616
1616
 
1617
+ // Provide a no-op pulse implementation for simple beacons
1618
+ useImperativeHandle(ref, () => ({ pulse: () => {} }), []);
1619
+
1617
1620
  // Calculate the target point position - project data to pixels
1618
1621
  const targetPoint = useDerivedValue(() => {
1619
1622
  if (!xScale || !yScale) return { x: 0, y: 0 };
@@ -1655,7 +1658,7 @@ function MonotoneAssetPrice() {
1655
1658
  <Circle c={animatedPoint} color={theme.color.fg} r={5} strokeWidth={3} style="stroke" />
1656
1659
  </>
1657
1660
  );
1658
- },
1661
+ }),
1659
1662
  );
1660
1663
 
1661
1664
  return (
@@ -146,67 +146,72 @@ You can use `BeaconComponent` to customize the visual appearance of scrubber bea
146
146
  ```jsx
147
147
  function OutlineBeacon() {
148
148
  // Simple outline beacon with no pulse animation
149
- const OutlineBeaconComponent = memo(({ dataX, dataY, seriesId, isIdle, animate = true }: ScrubberBeaconProps) => {
150
- const theme = useTheme();
151
- const { getSeries, getXSerializableScale, getYSerializableScale } = useCartesianChartContext();
149
+ const OutlineBeaconComponent = memo(
150
+ forwardRef(({ dataX, dataY, seriesId, isIdle, animate = true }: ScrubberBeaconProps, ref) => {
151
+ const theme = useTheme();
152
+ const { getSeries, getXSerializableScale, getYSerializableScale } = useCartesianChartContext();
153
+
154
+ const targetSeries = useMemo(() => getSeries(seriesId), [getSeries, seriesId]);
155
+ const xScale = useMemo(() => getXSerializableScale(), [getXSerializableScale]);
156
+ const yScale = useMemo(
157
+ () => getYSerializableScale(targetSeries?.yAxisId),
158
+ [getYSerializableScale, targetSeries?.yAxisId],
159
+ );
152
160
 
153
- const targetSeries = useMemo(() => getSeries(seriesId), [getSeries, seriesId]);
154
- const xScale = useMemo(() => getXSerializableScale(), [getXSerializableScale]);
155
- const yScale = useMemo(
156
- () => getYSerializableScale(targetSeries?.yAxisId),
157
- [getYSerializableScale, targetSeries?.yAxisId],
158
- );
161
+ const color = useMemo(
162
+ () => targetSeries?.color ?? theme.color.fgPrimary,
163
+ [targetSeries?.color, theme.color.fgPrimary],
164
+ );
159
165
 
160
- const color = useMemo(
161
- () => targetSeries?.color ?? theme.color.fgPrimary,
162
- [targetSeries?.color, theme.color.fgPrimary],
163
- );
166
+ const animatedX = useSharedValue(0);
167
+ const animatedY = useSharedValue(0);
164
168
 
165
- const animatedX = useSharedValue(0);
166
- const animatedY = useSharedValue(0);
167
-
168
- // Calculate the target point position - project data to pixels
169
- const targetPoint = useDerivedValue(() => {
170
- if (!xScale || !yScale) return { x: 0, y: 0 };
171
- return projectPointWithSerializableScale({
172
- x: unwrapAnimatedValue(dataX),
173
- y: unwrapAnimatedValue(dataY),
174
- xScale,
175
- yScale,
176
- });
177
- }, [dataX, dataY, xScale, yScale]);
178
-
179
- useAnimatedReaction(
180
- () => {
181
- return { point: targetPoint.value, isIdle: unwrapAnimatedValue(isIdle) };
182
- },
183
- (current, previous) => {
184
- // When animation is disabled, on initial render, or when we are starting,
185
- // continuing, or finishing scrubbing we should immediately transition
186
- if (!animate || previous === null || !previous.isIdle || !current.isIdle) {
187
- animatedX.value = current.point.x;
188
- animatedY.value = current.point.y;
189
- return;
190
- }
169
+ // Provide a no-op pulse implementation for simple beacons
170
+ useImperativeHandle(ref, () => ({ pulse: () => {} }), []);
191
171
 
192
- animatedX.value = buildTransition(current.point.x, defaultTransition);
193
- animatedY.value = buildTransition(current.point.y, defaultTransition);
194
- },
195
- [animate],
196
- );
172
+ // Calculate the target point position - project data to pixels
173
+ const targetPoint = useDerivedValue(() => {
174
+ if (!xScale || !yScale) return { x: 0, y: 0 };
175
+ return projectPointWithSerializableScale({
176
+ x: unwrapAnimatedValue(dataX),
177
+ y: unwrapAnimatedValue(dataY),
178
+ xScale,
179
+ yScale,
180
+ });
181
+ }, [dataX, dataY, xScale, yScale]);
197
182
 
198
- // Create animated point using the animated values
199
- const animatedPoint = useDerivedValue(() => {
200
- return { x: animatedX.value, y: animatedY.value };
201
- }, [animatedX, animatedY]);
183
+ useAnimatedReaction(
184
+ () => {
185
+ return { point: targetPoint.value, isIdle: unwrapAnimatedValue(isIdle) };
186
+ },
187
+ (current, previous) => {
188
+ // When animation is disabled, on initial render, or when we are starting,
189
+ // continuing, or finishing scrubbing we should immediately transition
190
+ if (!animate || previous === null || !previous.isIdle || !current.isIdle) {
191
+ animatedX.value = current.point.x;
192
+ animatedY.value = current.point.y;
193
+ return;
194
+ }
195
+
196
+ animatedX.value = buildTransition(current.point.x, defaultTransition);
197
+ animatedY.value = buildTransition(current.point.y, defaultTransition);
198
+ },
199
+ [animate],
200
+ );
202
201
 
203
- return (
204
- <>
205
- <Circle c={animatedPoint} color={color} r={6} />
206
- <Circle c={animatedPoint} color={theme.color.bg} r={3} />
207
- </>
208
- );
209
- });
202
+ // Create animated point using the animated values
203
+ const animatedPoint = useDerivedValue(() => {
204
+ return { x: animatedX.value, y: animatedY.value };
205
+ }, [animatedX, animatedY]);
206
+
207
+ return (
208
+ <>
209
+ <Circle c={animatedPoint} color={color} r={6} />
210
+ <Circle c={animatedPoint} color={theme.color.bg} r={3} />
211
+ </>
212
+ );
213
+ }),
214
+ );
210
215
 
211
216
  const dataCount = 14;
212
217
  const minDataValue = 0;
@@ -641,15 +646,17 @@ You can use `BeaconComponent` and `BeaconLabelComponent` with the `opacity` prop
641
646
 
642
647
  ```jsx
643
648
  function HiddenScrubberWhenIdle() {
644
- const MyScrubberBeacon = memo((props: ScrubberBeaconProps) => {
645
- const { scrubberPosition } = useScrubberContext();
646
- const beaconOpacity = useDerivedValue(
647
- () => (scrubberPosition.value !== undefined ? 1 : 0),
648
- [scrubberPosition],
649
- );
649
+ const MyScrubberBeacon = memo(
650
+ forwardRef((props: ScrubberBeaconProps, ref) => {
651
+ const { scrubberPosition } = useScrubberContext();
652
+ const beaconOpacity = useDerivedValue(
653
+ () => (scrubberPosition.value !== undefined ? 1 : 0),
654
+ [scrubberPosition],
655
+ );
650
656
 
651
- return <DefaultScrubberBeacon {...props} opacity={beaconOpacity} />;
652
- });
657
+ return <DefaultScrubberBeacon ref={ref} {...props} opacity={beaconOpacity} />;
658
+ }),
659
+ );
653
660
 
654
661
  const MyScrubberBeaconLabel = memo((props: ScrubberBeaconLabelProps) => {
655
662
  const { scrubberPosition } = useScrubberContext();
@@ -1527,45 +1527,50 @@ function MonotoneAssetPrice() {
1527
1527
  [scrubberPriceFormatter, prices, formatDate],
1528
1528
  );
1529
1529
 
1530
- const CustomScrubberBeacon = memo(({ dataX, dataY, seriesId, isIdle }: ScrubberBeaconProps) => {
1531
- const { getSeries, getXScale, getYScale } = useCartesianChartContext();
1532
- const targetSeries = getSeries(seriesId);
1533
- const xScale = getXScale();
1534
- const yScale = getYScale(targetSeries?.yAxisId);
1530
+ const CustomScrubberBeacon = memo(
1531
+ forwardRef(({ dataX, dataY, seriesId, isIdle }: ScrubberBeaconProps, ref) => {
1532
+ const { getSeries, getXScale, getYScale } = useCartesianChartContext();
1533
+ const targetSeries = getSeries(seriesId);
1534
+ const xScale = getXScale();
1535
+ const yScale = getYScale(targetSeries?.yAxisId);
1536
+
1537
+ const pixelCoordinate = useMemo(() => {
1538
+ if (!xScale || !yScale) return;
1539
+ return projectPoint({ x: dataX, y: dataY, xScale, yScale });
1540
+ }, [dataX, dataY, xScale, yScale]);
1535
1541
 
1536
- const pixelCoordinate = useMemo(() => {
1537
- if (!xScale || !yScale) return;
1538
- return projectPoint({ x: dataX, y: dataY, xScale, yScale });
1539
- }, [dataX, dataY, xScale, yScale]);
1542
+ // Provide a no-op pulse implementation for simple beacons
1543
+ useImperativeHandle(ref, () => ({ pulse: () => {} }), []);
1540
1544
 
1541
- if (!pixelCoordinate) return;
1545
+ if (!pixelCoordinate) return;
1546
+
1547
+ if (isIdle) {
1548
+ return (
1549
+ <m.circle
1550
+ animate={{ cx: pixelCoordinate.x, cy: pixelCoordinate.y }}
1551
+ cx={pixelCoordinate.x}
1552
+ cy={pixelCoordinate.y}
1553
+ fill="var(--color-bg)"
1554
+ r={5}
1555
+ stroke="var(--color-fg)"
1556
+ strokeWidth={3}
1557
+ transition={defaultTransition}
1558
+ />
1559
+ );
1560
+ }
1542
1561
 
1543
- if (isIdle) {
1544
1562
  return (
1545
- <m.circle
1546
- animate={{ cx: pixelCoordinate.x, cy: pixelCoordinate.y }}
1563
+ <circle
1547
1564
  cx={pixelCoordinate.x}
1548
1565
  cy={pixelCoordinate.y}
1549
1566
  fill="var(--color-bg)"
1550
1567
  r={5}
1551
1568
  stroke="var(--color-fg)"
1552
1569
  strokeWidth={3}
1553
- transition={defaultTransition}
1554
1570
  />
1555
1571
  );
1556
- }
1557
-
1558
- return (
1559
- <circle
1560
- cx={pixelCoordinate.x}
1561
- cy={pixelCoordinate.y}
1562
- fill="var(--color-bg)"
1563
- r={5}
1564
- stroke="var(--color-fg)"
1565
- strokeWidth={3}
1566
- />
1567
- );
1568
- });
1572
+ }),
1573
+ );
1569
1574
 
1570
1575
  return (
1571
1576
  <LineChart
@@ -63,14 +63,7 @@ function MyChart() {
63
63
  >
64
64
  <YAxis showGrid position="left" tickLabelFormatter={(value) => `$${value}`} />
65
65
  {prices.map((price, index) => (
66
- <Point
67
- seriesId="prices"
68
- key={index}
69
- dataX={index}
70
- dataY={price}
71
- label={`$${price}`}
72
- labelPosition="right"
73
- />
66
+ <Point key={index} dataX={index} dataY={price} label={`$${price}`} labelPosition="right" />
74
67
  ))}
75
68
  </CartesianChart>
76
69
  );
@@ -166,49 +166,54 @@ You can use `BeaconComponent` to customize the visual appearance of scrubber bea
166
166
  ```jsx live
167
167
  function OutlineBeacon() {
168
168
  // Simple outline beacon with no pulse animation
169
- const OutlineBeaconComponent = memo(({ dataX, dataY, seriesId, color, isIdle }: ScrubberBeaconProps) => {
170
- const { getSeries, getXScale, getYScale } = useCartesianChartContext();
171
- const targetSeries = getSeries(seriesId);
172
- const xScale = getXScale();
173
- const yScale = getYScale(targetSeries?.yAxisId);
174
-
175
- const pixelCoordinate = useMemo(() => {
176
- if (!xScale || !yScale) return;
177
- return projectPoint({ x: dataX, y: dataY, xScale, yScale });
178
- }, [dataX, dataY, xScale, yScale]);
179
-
180
- if (!pixelCoordinate) return;
169
+ const OutlineBeaconComponent = memo(
170
+ forwardRef(({ dataX, dataY, seriesId, color, isIdle }: ScrubberBeaconProps, ref) => {
171
+ const { getSeries, getXScale, getYScale } = useCartesianChartContext();
172
+ const targetSeries = getSeries(seriesId);
173
+ const xScale = getXScale();
174
+ const yScale = getYScale(targetSeries?.yAxisId);
175
+
176
+ const pixelCoordinate = useMemo(() => {
177
+ if (!xScale || !yScale) return;
178
+ return projectPoint({ x: dataX, y: dataY, xScale, yScale });
179
+ }, [dataX, dataY, xScale, yScale]);
180
+
181
+ // Provide a no-op pulse implementation for simple beacons
182
+ useImperativeHandle(ref, () => ({ pulse: () => {} }), []);
183
+
184
+ if (!pixelCoordinate) return;
185
+
186
+ if (isIdle) {
187
+ return (
188
+ <>
189
+ <m.circle
190
+ animate={{ cx: pixelCoordinate.x, cy: pixelCoordinate.y }}
191
+ cx={pixelCoordinate.x}
192
+ cy={pixelCoordinate.y}
193
+ transition={defaultTransition}
194
+ r={6}
195
+ fill={color}
196
+ />
197
+ <m.circle
198
+ animate={{ cx: pixelCoordinate.x, cy: pixelCoordinate.y }}
199
+ cx={pixelCoordinate.x}
200
+ cy={pixelCoordinate.y}
201
+ transition={defaultTransition}
202
+ r={3}
203
+ fill="var(--color-bg)"
204
+ />
205
+ </>
206
+ );
207
+ }
181
208
 
182
- if (isIdle) {
183
209
  return (
184
210
  <>
185
- <m.circle
186
- animate={{ cx: pixelCoordinate.x, cy: pixelCoordinate.y }}
187
- cx={pixelCoordinate.x}
188
- cy={pixelCoordinate.y}
189
- transition={defaultTransition}
190
- r={6}
191
- fill={color}
192
- />
193
- <m.circle
194
- animate={{ cx: pixelCoordinate.x, cy: pixelCoordinate.y }}
195
- cx={pixelCoordinate.x}
196
- cy={pixelCoordinate.y}
197
- transition={defaultTransition}
198
- r={3}
199
- fill="var(--color-bg)"
200
- />
211
+ <circle cx={pixelCoordinate.x} cy={pixelCoordinate.y} r={6} fill={color} />
212
+ <circle cx={pixelCoordinate.x} cy={pixelCoordinate.y} r={3} fill="var(--color-bg)" />
201
213
  </>
202
214
  );
203
- }
204
-
205
- return (
206
- <>
207
- <circle cx={pixelCoordinate.x} cy={pixelCoordinate.y} r={6} fill={color} />
208
- <circle cx={pixelCoordinate.x} cy={pixelCoordinate.y} r={3} fill="var(--color-bg)" />
209
- </>
210
- );
211
- });
215
+ }),
216
+ );
212
217
 
213
218
  const dataCount = 14;
214
219
  const minDataValue = 0;
@@ -541,12 +546,14 @@ You can use `BeaconComponent` and `BeaconLabelComponent` with the `opacity` prop
541
546
 
542
547
  ```jsx live
543
548
  function HiddenScrubberWhenIdle() {
544
- const MyScrubberBeacon = memo((props: ScrubberBeaconProps) => {
545
- const { scrubberPosition } = useScrubberContext();
546
- const isScrubbing = scrubberPosition !== undefined;
549
+ const MyScrubberBeacon = memo(
550
+ forwardRef((props: ScrubberBeaconProps, ref) => {
551
+ const { scrubberPosition } = useScrubberContext();
552
+ const isScrubbing = scrubberPosition !== undefined;
547
553
 
548
- return <DefaultScrubberBeacon {...props} opacity={isScrubbing ? 1 : 0} />;
549
- });
554
+ return <DefaultScrubberBeacon ref={ref} {...props} opacity={isScrubbing ? 1 : 0} />;
555
+ }),
556
+ );
550
557
 
551
558
  const MyScrubberBeaconLabel = memo((props: ScrubberBeaconLabelProps) => {
552
559
  const { scrubberPosition } = useScrubberContext();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coinbase/cds-mcp-server",
3
- "version": "8.27.1",
3
+ "version": "8.27.3",
4
4
  "description": "Coinbase Design System - MCP Server",
5
5
  "repository": {
6
6
  "type": "git",