@coinbase/cds-mcp-server 8.27.2 → 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 +4 -0
- package/mcp-docs/mobile/components/LineChart.txt +5 -2
- package/mcp-docs/mobile/components/Scrubber.txt +70 -63
- package/mcp-docs/web/components/LineChart.txt +32 -27
- package/mcp-docs/web/components/Point.txt +1 -8
- package/mcp-docs/web/components/Scrubber.txt +50 -43
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,10 @@ 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
|
+
|
|
11
15
|
## 8.27.2 ((12/4/2025, 04:23 PM PST))
|
|
12
16
|
|
|
13
17
|
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(
|
|
150
|
-
|
|
151
|
-
|
|
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
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
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
|
-
|
|
161
|
-
|
|
162
|
-
[targetSeries?.color, theme.color.fgPrimary],
|
|
163
|
-
);
|
|
166
|
+
const animatedX = useSharedValue(0);
|
|
167
|
+
const animatedY = useSharedValue(0);
|
|
164
168
|
|
|
165
|
-
|
|
166
|
-
|
|
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
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
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
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
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
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
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(
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
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
|
-
|
|
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(
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
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
|
-
|
|
1537
|
-
|
|
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
|
-
|
|
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
|
-
<
|
|
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(
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
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
|
-
<
|
|
186
|
-
|
|
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(
|
|
545
|
-
|
|
546
|
-
|
|
549
|
+
const MyScrubberBeacon = memo(
|
|
550
|
+
forwardRef((props: ScrubberBeaconProps, ref) => {
|
|
551
|
+
const { scrubberPosition } = useScrubberContext();
|
|
552
|
+
const isScrubbing = scrubberPosition !== undefined;
|
|
547
553
|
|
|
548
|
-
|
|
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();
|