@coinbase/cds-mcp-server 8.36.2 → 8.36.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,10 @@ All notable changes to this project will be documented in this file.
8
8
 
9
9
  <!-- template-start -->
10
10
 
11
+ ## 8.36.3 ((1/9/2026, 01:51 PM PST))
12
+
13
+ This is an artificial version bump with no new change.
14
+
11
15
  ## 8.36.2 ((1/7/2026, 10:19 AM PST))
12
16
 
13
17
  This is an artificial version bump with no new change.
@@ -381,6 +381,100 @@ function StepperCustomMetadataExample() {
381
381
  }
382
382
  ```
383
383
 
384
+ ##### Custom Step with Error State
385
+
386
+ You can create custom icon, label, and progress components for individual steps to show special states like errors.
387
+ In this example, the "Payment Method" step uses metadata to indicate an error condition. The custom components check this metadata and the completion state to dynamically render an error indicator, falling back to default components otherwise.
388
+
389
+ ```jsx
390
+ const ErrorStepperIcon = memo(function ErrorStepperIcon(props) {
391
+ const { step, visited, complete } = props;
392
+ const showError = step.metadata?.isError && (visited || complete);
393
+
394
+ if (!showError) {
395
+ return <DefaultStepperIconVertical {...props} />;
396
+ }
397
+
398
+ return (
399
+ <DefaultStepperIconVertical
400
+ {...props}
401
+ activeColor="bgNegative"
402
+ completeName="circleCross"
403
+ completeColor="bgNegative"
404
+ visitedName="circleCross"
405
+ visitedColor="bgNegative"
406
+ />
407
+ );
408
+ });
409
+
410
+ const ErrorStepperLabel = memo(function ErrorStepperLabel(props) {
411
+ const { step, visited, complete } = props;
412
+ const showError = step.metadata?.isError && (visited || complete);
413
+
414
+ if (!showError) {
415
+ return <DefaultStepperLabelVertical {...props} />;
416
+ }
417
+
418
+ return (
419
+ <DefaultStepperLabelVertical
420
+ {...props}
421
+ activeColor="fgNegative"
422
+ completeColor="fgNegative"
423
+ visitedColor="fgNegative"
424
+ />
425
+ );
426
+ });
427
+
428
+ const ErrorStepperProgress = memo(function ErrorStepperProgress(props) {
429
+ const { step, visited, complete } = props;
430
+ const showError = step.metadata?.isError && (visited || complete);
431
+
432
+ if (!showError) {
433
+ return <DefaultStepperProgressVertical {...props} />;
434
+ }
435
+
436
+ return (
437
+ <DefaultStepperProgressVertical {...props} completeFill="bgNegative" visitedFill="bgNegative" />
438
+ );
439
+ });
440
+
441
+ function StepperErrorStepExample() {
442
+ const steps = [
443
+ { id: '1', label: 'Account Details' },
444
+ { id: '2', label: 'Personal Information' },
445
+ {
446
+ id: '3',
447
+ label: 'Payment Method',
448
+ metadata: { isError: true },
449
+ },
450
+ { id: '4', label: 'Review & Submit' },
451
+ ];
452
+
453
+ const [stepperState, stepperApi] = useStepper({ steps });
454
+ const [complete, setComplete] = useState(false);
455
+
456
+ const handleNext = () => {
457
+ if (stepperState.activeStepId === '4') {
458
+ setComplete(true);
459
+ } else {
460
+ stepperApi.goNextStep();
461
+ }
462
+ };
463
+
464
+ return (
465
+ <Stepper
466
+ direction="vertical"
467
+ activeStepId={stepperState.activeStepId}
468
+ steps={steps}
469
+ complete={complete}
470
+ StepperIconComponent={ErrorStepperIcon}
471
+ StepperLabelComponent={ErrorStepperLabel}
472
+ StepperProgressComponent={ErrorStepperProgress}
473
+ />
474
+ );
475
+ }
476
+ ```
477
+
384
478
  #### 2. styles API
385
479
 
386
480
  The Stepper component provides flexible styling options through the `styles` prop.
@@ -355,6 +355,42 @@ function CustomGridLineExample() {
355
355
  }
356
356
  ```
357
357
 
358
+ On band scales, you can also use `bandGridLinePlacement` to control where grid lines appear relative to each band.
359
+
360
+ Using edges will place a grid line at the start of each band, plus a grid line at the end of the last band.
361
+
362
+ ```jsx
363
+ function BandGridPlacement() {
364
+ const [selectedBandGridPlacement, setSelectedBandGridPlacement] = useState('edges');
365
+
366
+ return (
367
+ <CartesianChart
368
+ height={250}
369
+ series={[
370
+ {
371
+ id: 'prices',
372
+ data: [10, 22, 29, 45, 98, 45, 22],
373
+ },
374
+ ]}
375
+ xAxis={{
376
+ scaleType: 'band',
377
+ data: ['April 1', 'April 2', 'April 3', 'April 4', 'April 5', 'April 6', 'April 7'],
378
+ }}
379
+ yAxis={{ domain: { min: 0 } }}
380
+ >
381
+ <XAxis
382
+ bandGridLinePlacement={selectedBandGridPlacement}
383
+ GridLineComponent={SolidLine}
384
+ showGrid
385
+ showLine
386
+ showTickMarks
387
+ />
388
+ <BarPlot />
389
+ </CartesianChart>
390
+ );
391
+ }
392
+ ```
393
+
358
394
  #### Line
359
395
 
360
396
  You can show the axis line using the `showLine` prop.
@@ -548,6 +584,41 @@ function XAxisTickMarksExample() {
548
584
  }
549
585
  ```
550
586
 
587
+ On band scales, you can also use `bandTickMarkPlacement` to control where tick marks appear relative to each band.
588
+
589
+ Using edges will place a tick mark at the start of each band, plus a tick mark at the end of the last band.
590
+
591
+ ```jsx
592
+ function BandTickMarkPlacement() {
593
+ const [selectedBandTickMarkPlacement, setSelectedBandTickMarkPlacement] = useState('middle');
594
+
595
+ return (
596
+ <CartesianChart
597
+ height={250}
598
+ series={[
599
+ {
600
+ id: 'prices',
601
+ data: [10, 22, 29, 45, 98, 45, 22],
602
+ },
603
+ ]}
604
+ xAxis={{
605
+ scaleType: 'band',
606
+ data: ['April 1', 'April 2', 'April 3', 'April 4', 'April 5', 'April 6', 'April 7'],
607
+ }}
608
+ yAxis={{ domain: { min: 0 } }}
609
+ >
610
+ <XAxis
611
+ bandTickMarkPlacement={selectedBandTickMarkPlacement}
612
+ showLine
613
+ showTickMarks
614
+ tickMarkSize={8}
615
+ />
616
+ <BarPlot />
617
+ </CartesianChart>
618
+ );
619
+ }
620
+ ```
621
+
551
622
  #### Tick Labels
552
623
 
553
624
  You can customize the tick labels using the `tickLabelFormatter` prop. It will receive the x data value of the tick. Meaning, if data is provided for the axis, it will receive the string label for the tick.
@@ -663,6 +734,8 @@ function CustomTickLabelExample() {
663
734
  | `LineComponent` | `LineComponent` | No | `SolidLine` | Component to render the axis line. |
664
735
  | `TickLabelComponent` | `AxisTickLabelComponent` | No | `DefaultAxisTickLabel` | Component to render tick labels. Allows for custom styling and formatting that works cross-platform. |
665
736
  | `TickMarkLineComponent` | `LineComponent` | No | `SolidLine` | Component to render the tick marks. |
737
+ | `bandGridLinePlacement` | `end \| start \| middle \| edges` | No | `'edges'` | Placement of grid lines relative to each band. Options: start, middle, end, edges |
738
+ | `bandTickMarkPlacement` | `end \| start \| middle \| edges` | No | `'middle'` | Placement of tick marks relative to each band. Options: start, middle, end, edges |
666
739
  | `height` | `number` | No | `32 when no label is provided, 52 when a label is provided` | Height of the axis. This value is inclusive of the padding. |
667
740
  | `label` | `string` | No | `-` | Label text to display for the axis. |
668
741
  | `labelGap` | `number` | No | `4` | Gap between the tick labels and the axis label. |
@@ -605,6 +605,8 @@ function MultipleYAxesExample() {
605
605
  | `TickLabelComponent` | `AxisTickLabelComponent` | No | `DefaultAxisTickLabel` | Component to render tick labels. Allows for custom styling and formatting that works cross-platform. |
606
606
  | `TickMarkLineComponent` | `LineComponent` | No | `SolidLine` | Component to render the tick marks. |
607
607
  | `axisId` | `string` | No | `-` | The ID of the axis to render. Defaults to defaultAxisId if not specified. |
608
+ | `bandGridLinePlacement` | `end \| start \| middle \| edges` | No | `'edges'` | Placement of grid lines relative to each band. Options: start, middle, end, edges |
609
+ | `bandTickMarkPlacement` | `end \| start \| middle \| edges` | No | `'middle'` | Placement of tick marks relative to each band. Options: start, middle, end, edges |
608
610
  | `label` | `string` | No | `-` | Label text to display for the axis. |
609
611
  | `labelGap` | `number` | No | `4` | Gap between the tick labels and the axis label. |
610
612
  | `minTickLabelGap` | `number` | No | `4` | Minimum gap between tick labels. Labels will be hidden if they are closer than this gap. |
@@ -725,8 +725,8 @@ function XAxisGradient() {
725
725
  | `userSelect` | `ResponsiveProp<text \| none \| all \| auto>` | No | `-` | - |
726
726
  | `visibility` | `ResponsiveProp<hidden \| visible>` | No | `-` | - |
727
727
  | `width` | `ResponsiveProp<Width<string \| number>>` | No | `-` | - |
728
- | `xAxis` | `(Partial<AxisConfigProps> & SharedProps & { label?: string; labelGap?: number \| undefined; minTickLabelGap?: number \| undefined; requestedTickCount?: number \| undefined; showGrid?: boolean \| undefined; showLine?: boolean \| undefined; showTickMarks?: boolean \| undefined; tickMarkSize?: number \| undefined; ticks?: number[] \| ((value: number) => boolean) \| undefined; tickMarkLabelGap?: number \| undefined; tickInterval?: number \| undefined; tickMinStep?: number \| undefined; tickMaxStep?: number \| undefined; } & { className?: string \| undefined; classNames?: { root?: string \| undefined; label?: string \| undefined; tickLabel?: string \| undefined; gridLine?: string \| undefined; line?: string \| undefined; tickMark?: string \| undefined; } \| undefined; style?: CSSProperties \| undefined; styles?: { root?: CSSProperties \| undefined; label?: CSSProperties \| undefined; tickLabel?: CSSProperties \| undefined; gridLine?: CSSProperties \| undefined; line?: CSSProperties \| undefined; tickMark?: CSSProperties \| undefined; } \| undefined; GridLineComponent?: LineComponent \| undefined; LineComponent?: LineComponent \| undefined; TickMarkLineComponent?: LineComponent \| undefined; tickLabelFormatter?: ((value: number) => ChartTextChildren) \| undefined; TickLabelComponent?: AxisTickLabelComponent \| undefined; } & { position?: top \| bottom \| undefined; height?: number \| undefined; }) \| undefined` | No | `-` | Configuration for x-axis. Accepts axis config and axis props. To show the axis, set showXAxis to true. |
729
- | `yAxis` | `(Partial<AxisConfigProps> & SharedProps & { label?: string; labelGap?: number \| undefined; minTickLabelGap?: number \| undefined; requestedTickCount?: number \| undefined; showGrid?: boolean \| undefined; showLine?: boolean \| undefined; showTickMarks?: boolean \| undefined; tickMarkSize?: number \| undefined; ticks?: number[] \| ((value: number) => boolean) \| undefined; tickMarkLabelGap?: number \| undefined; tickInterval?: number \| undefined; tickMinStep?: number \| undefined; tickMaxStep?: number \| undefined; } & { className?: string \| undefined; classNames?: { root?: string \| undefined; label?: string \| undefined; tickLabel?: string \| undefined; gridLine?: string \| undefined; line?: string \| undefined; tickMark?: string \| undefined; } \| undefined; style?: CSSProperties \| undefined; styles?: { root?: CSSProperties \| undefined; label?: CSSProperties \| undefined; tickLabel?: CSSProperties \| undefined; gridLine?: CSSProperties \| undefined; line?: CSSProperties \| undefined; tickMark?: CSSProperties \| undefined; } \| undefined; GridLineComponent?: LineComponent \| undefined; LineComponent?: LineComponent \| undefined; TickMarkLineComponent?: LineComponent \| undefined; tickLabelFormatter?: ((value: number) => ChartTextChildren) \| undefined; TickLabelComponent?: AxisTickLabelComponent \| undefined; } & { axisId?: string \| undefined; position?: left \| right \| undefined; width?: number \| undefined; }) \| undefined` | No | `-` | Configuration for y-axis. Accepts axis config and axis props. To show the axis, set showYAxis to true. |
728
+ | `xAxis` | `(Partial<AxisConfigProps> & SharedProps & { bandGridLinePlacement?: AxisBandPlacement; bandTickMarkPlacement?: AxisBandPlacement \| undefined; label?: string \| undefined; labelGap?: number \| undefined; minTickLabelGap?: number \| undefined; requestedTickCount?: number \| undefined; showGrid?: boolean \| undefined; showLine?: boolean \| undefined; showTickMarks?: boolean \| undefined; tickMarkSize?: number \| undefined; ticks?: number[] \| ((value: number) => boolean) \| undefined; tickMarkLabelGap?: number \| undefined; tickInterval?: number \| undefined; tickMinStep?: number \| undefined; tickMaxStep?: number \| undefined; } & { className?: string \| undefined; classNames?: { root?: string \| undefined; label?: string \| undefined; tickLabel?: string \| undefined; gridLine?: string \| undefined; line?: string \| undefined; tickMark?: string \| undefined; } \| undefined; style?: CSSProperties \| undefined; styles?: { root?: CSSProperties \| undefined; label?: CSSProperties \| undefined; tickLabel?: CSSProperties \| undefined; gridLine?: CSSProperties \| undefined; line?: CSSProperties \| undefined; tickMark?: CSSProperties \| undefined; } \| undefined; GridLineComponent?: LineComponent \| undefined; LineComponent?: LineComponent \| undefined; TickMarkLineComponent?: LineComponent \| undefined; tickLabelFormatter?: ((value: number) => ChartTextChildren) \| undefined; TickLabelComponent?: AxisTickLabelComponent \| undefined; } & { position?: top \| bottom \| undefined; height?: number \| undefined; }) \| undefined` | No | `-` | Configuration for x-axis. Accepts axis config and axis props. To show the axis, set showXAxis to true. |
729
+ | `yAxis` | `(Partial<AxisConfigProps> & SharedProps & { bandGridLinePlacement?: AxisBandPlacement; bandTickMarkPlacement?: AxisBandPlacement \| undefined; label?: string \| undefined; labelGap?: number \| undefined; minTickLabelGap?: number \| undefined; requestedTickCount?: number \| undefined; showGrid?: boolean \| undefined; showLine?: boolean \| undefined; showTickMarks?: boolean \| undefined; tickMarkSize?: number \| undefined; ticks?: number[] \| ((value: number) => boolean) \| undefined; tickMarkLabelGap?: number \| undefined; tickInterval?: number \| undefined; tickMinStep?: number \| undefined; tickMaxStep?: number \| undefined; } & { className?: string \| undefined; classNames?: { root?: string \| undefined; label?: string \| undefined; tickLabel?: string \| undefined; gridLine?: string \| undefined; line?: string \| undefined; tickMark?: string \| undefined; } \| undefined; style?: CSSProperties \| undefined; styles?: { root?: CSSProperties \| undefined; label?: CSSProperties \| undefined; tickLabel?: CSSProperties \| undefined; gridLine?: CSSProperties \| undefined; line?: CSSProperties \| undefined; tickMark?: CSSProperties \| undefined; } \| undefined; GridLineComponent?: LineComponent \| undefined; LineComponent?: LineComponent \| undefined; TickMarkLineComponent?: LineComponent \| undefined; tickLabelFormatter?: ((value: number) => ChartTextChildren) \| undefined; TickLabelComponent?: AxisTickLabelComponent \| undefined; } & { axisId?: string \| undefined; position?: left \| right \| undefined; width?: number \| undefined; }) \| undefined` | No | `-` | Configuration for y-axis. Accepts axis config and axis props. To show the axis, set showYAxis to true. |
730
730
  | `zIndex` | `inherit \| auto \| revert \| -moz-initial \| initial \| revert-layer \| unset` | No | `-` | - |
731
731
 
732
732
 
@@ -1129,8 +1129,8 @@ function UpdatingChartValues() {
1129
1129
  | `userSelect` | `ResponsiveProp<text \| none \| all \| auto>` | No | `-` | - |
1130
1130
  | `visibility` | `ResponsiveProp<hidden \| visible>` | No | `-` | - |
1131
1131
  | `width` | `ResponsiveProp<Width<string \| number>>` | No | `-` | - |
1132
- | `xAxis` | `(Partial<AxisConfigProps> & SharedProps & { label?: string; labelGap?: number \| undefined; minTickLabelGap?: number \| undefined; requestedTickCount?: number \| undefined; showGrid?: boolean \| undefined; showLine?: boolean \| undefined; showTickMarks?: boolean \| undefined; tickMarkSize?: number \| undefined; ticks?: number[] \| ((value: number) => boolean) \| undefined; tickMarkLabelGap?: number \| undefined; tickInterval?: number \| undefined; tickMinStep?: number \| undefined; tickMaxStep?: number \| undefined; } & { className?: string \| undefined; classNames?: { root?: string \| undefined; label?: string \| undefined; tickLabel?: string \| undefined; gridLine?: string \| undefined; line?: string \| undefined; tickMark?: string \| undefined; } \| undefined; style?: CSSProperties \| undefined; styles?: { root?: CSSProperties \| undefined; label?: CSSProperties \| undefined; tickLabel?: CSSProperties \| undefined; gridLine?: CSSProperties \| undefined; line?: CSSProperties \| undefined; tickMark?: CSSProperties \| undefined; } \| undefined; GridLineComponent?: LineComponent \| undefined; LineComponent?: LineComponent \| undefined; TickMarkLineComponent?: LineComponent \| undefined; tickLabelFormatter?: ((value: number) => ChartTextChildren) \| undefined; TickLabelComponent?: AxisTickLabelComponent \| undefined; } & { position?: top \| bottom \| undefined; height?: number \| undefined; }) \| undefined` | No | `-` | Configuration for x-axis. Accepts axis config and axis props. To show the axis, set showXAxis to true. |
1133
- | `yAxis` | `(Partial<AxisConfigProps> & SharedProps & { label?: string; labelGap?: number \| undefined; minTickLabelGap?: number \| undefined; requestedTickCount?: number \| undefined; showGrid?: boolean \| undefined; showLine?: boolean \| undefined; showTickMarks?: boolean \| undefined; tickMarkSize?: number \| undefined; ticks?: number[] \| ((value: number) => boolean) \| undefined; tickMarkLabelGap?: number \| undefined; tickInterval?: number \| undefined; tickMinStep?: number \| undefined; tickMaxStep?: number \| undefined; } & { className?: string \| undefined; classNames?: { root?: string \| undefined; label?: string \| undefined; tickLabel?: string \| undefined; gridLine?: string \| undefined; line?: string \| undefined; tickMark?: string \| undefined; } \| undefined; style?: CSSProperties \| undefined; styles?: { root?: CSSProperties \| undefined; label?: CSSProperties \| undefined; tickLabel?: CSSProperties \| undefined; gridLine?: CSSProperties \| undefined; line?: CSSProperties \| undefined; tickMark?: CSSProperties \| undefined; } \| undefined; GridLineComponent?: LineComponent \| undefined; LineComponent?: LineComponent \| undefined; TickMarkLineComponent?: LineComponent \| undefined; tickLabelFormatter?: ((value: number) => ChartTextChildren) \| undefined; TickLabelComponent?: AxisTickLabelComponent \| undefined; } & { axisId?: string \| undefined; position?: left \| right \| undefined; width?: number \| undefined; }) \| undefined` | No | `-` | Configuration for y-axis. Accepts axis config and axis props. To show the axis, set showYAxis to true. |
1132
+ | `xAxis` | `(Partial<AxisConfigProps> & SharedProps & { bandGridLinePlacement?: AxisBandPlacement; bandTickMarkPlacement?: AxisBandPlacement \| undefined; label?: string \| undefined; labelGap?: number \| undefined; minTickLabelGap?: number \| undefined; requestedTickCount?: number \| undefined; showGrid?: boolean \| undefined; showLine?: boolean \| undefined; showTickMarks?: boolean \| undefined; tickMarkSize?: number \| undefined; ticks?: number[] \| ((value: number) => boolean) \| undefined; tickMarkLabelGap?: number \| undefined; tickInterval?: number \| undefined; tickMinStep?: number \| undefined; tickMaxStep?: number \| undefined; } & { className?: string \| undefined; classNames?: { root?: string \| undefined; label?: string \| undefined; tickLabel?: string \| undefined; gridLine?: string \| undefined; line?: string \| undefined; tickMark?: string \| undefined; } \| undefined; style?: CSSProperties \| undefined; styles?: { root?: CSSProperties \| undefined; label?: CSSProperties \| undefined; tickLabel?: CSSProperties \| undefined; gridLine?: CSSProperties \| undefined; line?: CSSProperties \| undefined; tickMark?: CSSProperties \| undefined; } \| undefined; GridLineComponent?: LineComponent \| undefined; LineComponent?: LineComponent \| undefined; TickMarkLineComponent?: LineComponent \| undefined; tickLabelFormatter?: ((value: number) => ChartTextChildren) \| undefined; TickLabelComponent?: AxisTickLabelComponent \| undefined; } & { position?: top \| bottom \| undefined; height?: number \| undefined; }) \| undefined` | No | `-` | Configuration for x-axis. Accepts axis config and axis props. To show the axis, set showXAxis to true. |
1133
+ | `yAxis` | `(Partial<AxisConfigProps> & SharedProps & { bandGridLinePlacement?: AxisBandPlacement; bandTickMarkPlacement?: AxisBandPlacement \| undefined; label?: string \| undefined; labelGap?: number \| undefined; minTickLabelGap?: number \| undefined; requestedTickCount?: number \| undefined; showGrid?: boolean \| undefined; showLine?: boolean \| undefined; showTickMarks?: boolean \| undefined; tickMarkSize?: number \| undefined; ticks?: number[] \| ((value: number) => boolean) \| undefined; tickMarkLabelGap?: number \| undefined; tickInterval?: number \| undefined; tickMinStep?: number \| undefined; tickMaxStep?: number \| undefined; } & { className?: string \| undefined; classNames?: { root?: string \| undefined; label?: string \| undefined; tickLabel?: string \| undefined; gridLine?: string \| undefined; line?: string \| undefined; tickMark?: string \| undefined; } \| undefined; style?: CSSProperties \| undefined; styles?: { root?: CSSProperties \| undefined; label?: CSSProperties \| undefined; tickLabel?: CSSProperties \| undefined; gridLine?: CSSProperties \| undefined; line?: CSSProperties \| undefined; tickMark?: CSSProperties \| undefined; } \| undefined; GridLineComponent?: LineComponent \| undefined; LineComponent?: LineComponent \| undefined; TickMarkLineComponent?: LineComponent \| undefined; tickLabelFormatter?: ((value: number) => ChartTextChildren) \| undefined; TickLabelComponent?: AxisTickLabelComponent \| undefined; } & { axisId?: string \| undefined; position?: left \| right \| undefined; width?: number \| undefined; }) \| undefined` | No | `-` | Configuration for y-axis. Accepts axis config and axis props. To show the axis, set showYAxis to true. |
1134
1134
  | `zIndex` | `inherit \| auto \| revert \| -moz-initial \| initial \| revert-layer \| unset` | No | `-` | - |
1135
1135
 
1136
1136
 
@@ -2052,8 +2052,8 @@ function ForecastAssetPrice() {
2052
2052
  | `userSelect` | `ResponsiveProp<text \| none \| all \| auto>` | No | `-` | - |
2053
2053
  | `visibility` | `ResponsiveProp<hidden \| visible>` | No | `-` | - |
2054
2054
  | `width` | `ResponsiveProp<Width<string \| number>>` | No | `-` | - |
2055
- | `xAxis` | `(Partial<AxisConfigProps> & SharedProps & { label?: string; labelGap?: number \| undefined; minTickLabelGap?: number \| undefined; requestedTickCount?: number \| undefined; showGrid?: boolean \| undefined; showLine?: boolean \| undefined; showTickMarks?: boolean \| undefined; tickMarkSize?: number \| undefined; ticks?: number[] \| ((value: number) => boolean) \| undefined; tickMarkLabelGap?: number \| undefined; tickInterval?: number \| undefined; tickMinStep?: number \| undefined; tickMaxStep?: number \| undefined; } & { className?: string \| undefined; classNames?: { root?: string \| undefined; label?: string \| undefined; tickLabel?: string \| undefined; gridLine?: string \| undefined; line?: string \| undefined; tickMark?: string \| undefined; } \| undefined; style?: CSSProperties \| undefined; styles?: { root?: CSSProperties \| undefined; label?: CSSProperties \| undefined; tickLabel?: CSSProperties \| undefined; gridLine?: CSSProperties \| undefined; line?: CSSProperties \| undefined; tickMark?: CSSProperties \| undefined; } \| undefined; GridLineComponent?: LineComponent \| undefined; LineComponent?: LineComponent \| undefined; TickMarkLineComponent?: LineComponent \| undefined; tickLabelFormatter?: ((value: number) => ChartTextChildren) \| undefined; TickLabelComponent?: AxisTickLabelComponent \| undefined; } & { position?: top \| bottom \| undefined; height?: number \| undefined; }) \| undefined` | No | `-` | Configuration for x-axis. Accepts axis config and axis props. To show the axis, set showXAxis to true. |
2056
- | `yAxis` | `(Partial<AxisConfigProps> & SharedProps & { label?: string; labelGap?: number \| undefined; minTickLabelGap?: number \| undefined; requestedTickCount?: number \| undefined; showGrid?: boolean \| undefined; showLine?: boolean \| undefined; showTickMarks?: boolean \| undefined; tickMarkSize?: number \| undefined; ticks?: number[] \| ((value: number) => boolean) \| undefined; tickMarkLabelGap?: number \| undefined; tickInterval?: number \| undefined; tickMinStep?: number \| undefined; tickMaxStep?: number \| undefined; } & { className?: string \| undefined; classNames?: { root?: string \| undefined; label?: string \| undefined; tickLabel?: string \| undefined; gridLine?: string \| undefined; line?: string \| undefined; tickMark?: string \| undefined; } \| undefined; style?: CSSProperties \| undefined; styles?: { root?: CSSProperties \| undefined; label?: CSSProperties \| undefined; tickLabel?: CSSProperties \| undefined; gridLine?: CSSProperties \| undefined; line?: CSSProperties \| undefined; tickMark?: CSSProperties \| undefined; } \| undefined; GridLineComponent?: LineComponent \| undefined; LineComponent?: LineComponent \| undefined; TickMarkLineComponent?: LineComponent \| undefined; tickLabelFormatter?: ((value: number) => ChartTextChildren) \| undefined; TickLabelComponent?: AxisTickLabelComponent \| undefined; } & { axisId?: string \| undefined; position?: left \| right \| undefined; width?: number \| undefined; }) \| undefined` | No | `-` | Configuration for y-axis. Accepts axis config and axis props. To show the axis, set showYAxis to true. |
2055
+ | `xAxis` | `(Partial<AxisConfigProps> & SharedProps & { bandGridLinePlacement?: AxisBandPlacement; bandTickMarkPlacement?: AxisBandPlacement \| undefined; label?: string \| undefined; labelGap?: number \| undefined; minTickLabelGap?: number \| undefined; requestedTickCount?: number \| undefined; showGrid?: boolean \| undefined; showLine?: boolean \| undefined; showTickMarks?: boolean \| undefined; tickMarkSize?: number \| undefined; ticks?: number[] \| ((value: number) => boolean) \| undefined; tickMarkLabelGap?: number \| undefined; tickInterval?: number \| undefined; tickMinStep?: number \| undefined; tickMaxStep?: number \| undefined; } & { className?: string \| undefined; classNames?: { root?: string \| undefined; label?: string \| undefined; tickLabel?: string \| undefined; gridLine?: string \| undefined; line?: string \| undefined; tickMark?: string \| undefined; } \| undefined; style?: CSSProperties \| undefined; styles?: { root?: CSSProperties \| undefined; label?: CSSProperties \| undefined; tickLabel?: CSSProperties \| undefined; gridLine?: CSSProperties \| undefined; line?: CSSProperties \| undefined; tickMark?: CSSProperties \| undefined; } \| undefined; GridLineComponent?: LineComponent \| undefined; LineComponent?: LineComponent \| undefined; TickMarkLineComponent?: LineComponent \| undefined; tickLabelFormatter?: ((value: number) => ChartTextChildren) \| undefined; TickLabelComponent?: AxisTickLabelComponent \| undefined; } & { position?: top \| bottom \| undefined; height?: number \| undefined; }) \| undefined` | No | `-` | Configuration for x-axis. Accepts axis config and axis props. To show the axis, set showXAxis to true. |
2056
+ | `yAxis` | `(Partial<AxisConfigProps> & SharedProps & { bandGridLinePlacement?: AxisBandPlacement; bandTickMarkPlacement?: AxisBandPlacement \| undefined; label?: string \| undefined; labelGap?: number \| undefined; minTickLabelGap?: number \| undefined; requestedTickCount?: number \| undefined; showGrid?: boolean \| undefined; showLine?: boolean \| undefined; showTickMarks?: boolean \| undefined; tickMarkSize?: number \| undefined; ticks?: number[] \| ((value: number) => boolean) \| undefined; tickMarkLabelGap?: number \| undefined; tickInterval?: number \| undefined; tickMinStep?: number \| undefined; tickMaxStep?: number \| undefined; } & { className?: string \| undefined; classNames?: { root?: string \| undefined; label?: string \| undefined; tickLabel?: string \| undefined; gridLine?: string \| undefined; line?: string \| undefined; tickMark?: string \| undefined; } \| undefined; style?: CSSProperties \| undefined; styles?: { root?: CSSProperties \| undefined; label?: CSSProperties \| undefined; tickLabel?: CSSProperties \| undefined; gridLine?: CSSProperties \| undefined; line?: CSSProperties \| undefined; tickMark?: CSSProperties \| undefined; } \| undefined; GridLineComponent?: LineComponent \| undefined; LineComponent?: LineComponent \| undefined; TickMarkLineComponent?: LineComponent \| undefined; tickLabelFormatter?: ((value: number) => ChartTextChildren) \| undefined; TickLabelComponent?: AxisTickLabelComponent \| undefined; } & { axisId?: string \| undefined; position?: left \| right \| undefined; width?: number \| undefined; }) \| undefined` | No | `-` | Configuration for y-axis. Accepts axis config and axis props. To show the axis, set showYAxis to true. |
2057
2057
  | `zIndex` | `inherit \| auto \| revert \| -moz-initial \| initial \| revert-layer \| unset` | No | `-` | - |
2058
2058
 
2059
2059
 
@@ -76,6 +76,92 @@ function Example() {
76
76
  }
77
77
  ```
78
78
 
79
+ ### Chained Modals
80
+
81
+ :::tip Accessibility tip
82
+ For chained modals, set `restoreFocusOnUnmount={false}` on each one and return focus to the opener when exiting the chain (e.g., `triggerRef.current?.focus()`) to keep tab order predictable.
83
+ :::
84
+
85
+ ```jsx live
86
+ function ChainedModalsExample() {
87
+ const triggerRef = useRef(null);
88
+ const [isFirstModalOpen, setIsFirstModalOpen] = useState(false);
89
+ const [isSecondModalOpen, setIsSecondModalOpen] = useState(false);
90
+
91
+ const closeFirstModal = () => {
92
+ setIsFirstModalOpen(false);
93
+ triggerRef.current?.focus();
94
+ };
95
+
96
+ const openSecondModal = () => {
97
+ setIsFirstModalOpen(false);
98
+ setIsSecondModalOpen(true);
99
+ };
100
+
101
+ const closeSecondModal = () => {
102
+ setIsSecondModalOpen(false);
103
+ triggerRef.current?.focus();
104
+ };
105
+
106
+ const goBackToFirstModal = () => {
107
+ setIsSecondModalOpen(false);
108
+ setIsFirstModalOpen(true);
109
+ };
110
+
111
+ return (
112
+ <>
113
+ <Button ref={triggerRef} onClick={() => setIsFirstModalOpen(true)}>
114
+ Open Modal
115
+ </Button>
116
+ <Modal
117
+ onRequestClose={closeFirstModal}
118
+ restoreFocusOnUnmount={false}
119
+ visible={isFirstModalOpen}
120
+ >
121
+ <ModalHeader
122
+ closeAccessibilityLabel="Close"
123
+ onBackButtonClick={closeFirstModal}
124
+ title="First Modal"
125
+ />
126
+ <ModalBody tabIndex={0} testID="first-modal-body">
127
+ <Text>First modal content</Text>
128
+ </ModalBody>
129
+ <ModalFooter
130
+ primaryAction={<Button onClick={openSecondModal}>Next</Button>}
131
+ secondaryAction={
132
+ <Button onClick={closeFirstModal} variant="secondary">
133
+ Cancel
134
+ </Button>
135
+ }
136
+ />
137
+ </Modal>
138
+ <Modal
139
+ onRequestClose={closeSecondModal}
140
+ restoreFocusOnUnmount={false}
141
+ visible={isSecondModalOpen}
142
+ >
143
+ <ModalHeader
144
+ closeAccessibilityLabel="Close"
145
+ onBackButtonClick={goBackToFirstModal}
146
+ title="Second Modal"
147
+ />
148
+ <ModalBody tabIndex={0} testID="second-modal-body">
149
+ <Text>Second modal content</Text>
150
+ </ModalBody>
151
+ <ModalFooter
152
+ primaryAction={<Button onClick={closeSecondModal}>Close</Button>}
153
+ secondaryAction={
154
+ <Button onClick={closeSecondModal} variant="secondary">
155
+ Cancel
156
+ </Button>
157
+ }
158
+ />
159
+ </Modal>
160
+ </>
161
+ );
162
+ }
163
+ ```
164
+
79
165
  ## Props
80
166
 
81
167
  | Prop | Type | Required | Default | Description |
@@ -497,6 +497,141 @@ function StepperCustomMetadataExample() {
497
497
  }
498
498
  ```
499
499
 
500
+ ##### Custom Step with Error State
501
+
502
+ You can create custom icon, label, and progress components for individual steps to show special states like errors.
503
+ In this example, the "Payment Method" step uses metadata to indicate an error condition. The custom components check this metadata and the completion state to dynamically render an error indicator, falling back to default components otherwise.
504
+
505
+ ```jsx live
506
+ function StepperErrorStepExample() {
507
+ const ErrorStepperIcon = useMemo(
508
+ () =>
509
+ memo(function ErrorStepperIcon(props) {
510
+ const { step, visited, complete } = props;
511
+ const showError = step.metadata?.isError && (visited || complete);
512
+
513
+ if (!showError) {
514
+ return <DefaultStepperIconVertical {...props} />;
515
+ }
516
+
517
+ return (
518
+ <DefaultStepperIconVertical
519
+ {...props}
520
+ activeColor="bgNegative"
521
+ completeName="circleCross"
522
+ completeColor="bgNegative"
523
+ visitedName="circleCross"
524
+ visitedColor="bgNegative"
525
+ />
526
+ );
527
+ }),
528
+ [],
529
+ );
530
+
531
+ const ErrorStepperLabel = useMemo(
532
+ () =>
533
+ memo(function ErrorStepperLabel(props) {
534
+ const { step, visited, complete } = props;
535
+ const showError = step.metadata?.isError && (visited || complete);
536
+
537
+ if (!showError) {
538
+ return <DefaultStepperLabelVertical {...props} />;
539
+ }
540
+
541
+ return (
542
+ <DefaultStepperLabelVertical
543
+ {...props}
544
+ activeColor="fgNegative"
545
+ completeColor="fgNegative"
546
+ visitedColor="fgNegative"
547
+ />
548
+ );
549
+ }),
550
+ [],
551
+ );
552
+
553
+ const ErrorStepperProgress = useMemo(
554
+ () =>
555
+ memo(function ErrorStepperProgress(props) {
556
+ const { step, visited, complete } = props;
557
+ const showError = step.metadata?.isError && (visited || complete);
558
+
559
+ if (!showError) {
560
+ return <DefaultStepperProgressVertical {...props} />;
561
+ }
562
+
563
+ return (
564
+ <DefaultStepperProgressVertical
565
+ {...props}
566
+ completeFill="bgNegative"
567
+ visitedFill="bgNegative"
568
+ />
569
+ );
570
+ }),
571
+ [],
572
+ );
573
+
574
+ const steps = [
575
+ { id: '1', label: 'Account Details' },
576
+ { id: '2', label: 'Personal Information' },
577
+ {
578
+ id: '3',
579
+ label: 'Payment Method',
580
+ metadata: { isError: true },
581
+ },
582
+ { id: '4', label: 'Review & Submit' },
583
+ ];
584
+
585
+ const [stepperState, stepperApi] = useStepper({ steps });
586
+ const [complete, setComplete] = useState(false);
587
+
588
+ const handleNext = () => {
589
+ if (stepperState.activeStepId === '4') {
590
+ setComplete(true);
591
+ } else {
592
+ stepperApi.goNextStep();
593
+ }
594
+ };
595
+
596
+ const handlePrevious = () => {
597
+ setComplete(false);
598
+ stepperApi.goPreviousStep();
599
+ };
600
+
601
+ const handleReset = () => {
602
+ setComplete(false);
603
+ stepperApi.reset();
604
+ };
605
+
606
+ return (
607
+ <VStack gap={2}>
608
+ <Stepper
609
+ direction="vertical"
610
+ activeStepId={stepperState.activeStepId}
611
+ steps={steps}
612
+ complete={complete}
613
+ StepperIconComponent={ErrorStepperIcon}
614
+ StepperLabelComponent={ErrorStepperLabel}
615
+ StepperProgressComponent={ErrorStepperProgress}
616
+ />
617
+ <HStack gap={1}>
618
+ <Button
619
+ variant="secondary"
620
+ onClick={handlePrevious}
621
+ disabled={stepperState.activeStepId === '1'}
622
+ >
623
+ Previous
624
+ </Button>
625
+ <Button onClick={handleNext} disabled={complete}>
626
+ {stepperState.activeStepId === '4' ? 'Complete' : 'Next'}
627
+ </Button>
628
+ {complete && <Button onClick={handleReset}>Reset</Button>}
629
+ </HStack>
630
+ </VStack>
631
+ );
632
+ }
633
+ ```
634
+
500
635
  #### 2. style and className APIs
501
636
 
502
637
  The Stepper component provides flexible styling options through the `classNames` and `styles` props.
@@ -354,6 +354,62 @@ function CustomGridLineExample() {
354
354
  }
355
355
  ```
356
356
 
357
+ On band scales, you can also use `bandGridLinePlacement` to control where grid lines appear relative to each band.
358
+
359
+ Using edges will place a grid line at the start of each band, plus a grid line at the end of the last band.
360
+
361
+ ```jsx live
362
+ function BandGridPlacement() {
363
+ const bandGridLinePlacements = [
364
+ { id: 'edges', label: 'Edges' },
365
+ { id: 'start', label: 'Start' },
366
+ { id: 'middle', label: 'Middle' },
367
+ { id: 'end', label: 'End' },
368
+ ];
369
+ const [selectedBandGridPlacement, setSelectedBandGridPlacement] = useState(
370
+ bandGridLinePlacements[0],
371
+ );
372
+
373
+ return (
374
+ <VStack gap={2}>
375
+ <HStack justifyContent="flex-end" gap={2} alignItems="center">
376
+ <Text as="h3" font="headline">
377
+ Band Grid Placement
378
+ </Text>
379
+ <SegmentedTabs
380
+ activeTab={selectedBandGridPlacement}
381
+ onChange={setSelectedBandGridPlacement}
382
+ tabs={bandGridLinePlacements}
383
+ />
384
+ </HStack>
385
+ <CartesianChart
386
+ height={250}
387
+ series={[
388
+ {
389
+ id: 'prices',
390
+ data: [10, 22, 29, 45, 98, 45, 22],
391
+ },
392
+ ]}
393
+ xAxis={{
394
+ scaleType: 'band',
395
+ data: ['April 1', 'April 2', 'April 3', 'April 4', 'April 5', 'April 6', 'April 7'],
396
+ }}
397
+ yAxis={{ domain: { min: 0 } }}
398
+ >
399
+ <XAxis
400
+ bandGridLinePlacement={selectedBandGridPlacement.id}
401
+ GridLineComponent={SolidLine}
402
+ showGrid
403
+ showLine
404
+ showTickMarks
405
+ />
406
+ <BarPlot />
407
+ </CartesianChart>
408
+ </VStack>
409
+ );
410
+ }
411
+ ```
412
+
357
413
  #### Line
358
414
 
359
415
  You can show the axis line using the `showLine` prop.
@@ -546,6 +602,61 @@ function XAxisTickMarksExample() {
546
602
  }
547
603
  ```
548
604
 
605
+ On band scales, you can also use `bandTickMarkPlacement` to control where tick marks appear relative to each band.
606
+
607
+ Using edges will place a tick mark at the start of each band, plus a tick mark at the end of the last band.
608
+
609
+ ```jsx live
610
+ function BandTickMarkPlacement() {
611
+ const bandTickMarkPlacements = [
612
+ { id: 'middle', label: 'Middle' },
613
+ { id: 'edges', label: 'Edges' },
614
+ { id: 'start', label: 'Start' },
615
+ { id: 'end', label: 'End' },
616
+ ];
617
+ const [selectedBandTickMarkPlacement, setSelectedBandTickMarkPlacement] = useState(
618
+ bandTickMarkPlacements[0],
619
+ );
620
+
621
+ return (
622
+ <VStack gap={2}>
623
+ <HStack justifyContent="flex-end" gap={2} alignItems="center">
624
+ <Text as="h3" font="headline">
625
+ Band Tick Mark Placement
626
+ </Text>
627
+ <SegmentedTabs
628
+ activeTab={selectedBandTickMarkPlacement}
629
+ onChange={setSelectedBandTickMarkPlacement}
630
+ tabs={bandTickMarkPlacements}
631
+ />
632
+ </HStack>
633
+ <CartesianChart
634
+ height={250}
635
+ series={[
636
+ {
637
+ id: 'prices',
638
+ data: [10, 22, 29, 45, 98, 45, 22],
639
+ },
640
+ ]}
641
+ xAxis={{
642
+ scaleType: 'band',
643
+ data: ['April 1', 'April 2', 'April 3', 'April 4', 'April 5', 'April 6', 'April 7'],
644
+ }}
645
+ yAxis={{ domain: { min: 0 } }}
646
+ >
647
+ <XAxis
648
+ bandTickMarkPlacement={selectedBandTickMarkPlacement.id}
649
+ showLine
650
+ showTickMarks
651
+ tickMarkSize={8}
652
+ />
653
+ <BarPlot />
654
+ </CartesianChart>
655
+ </VStack>
656
+ );
657
+ }
658
+ ```
659
+
549
660
  #### Tick Labels
550
661
 
551
662
  You can customize the tick labels using the `tickLabelFormatter` prop. It will receive the x data value of the tick. Meaning, if data is provided for the axis, it will receive the string label for the tick.
@@ -659,6 +770,8 @@ function CustomTickLabelExample() {
659
770
  | `LineComponent` | `LineComponent` | No | `SolidLine` | Component to render the axis line. |
660
771
  | `TickLabelComponent` | `AxisTickLabelComponent` | No | `DefaultAxisTickLabel` | Component to render tick labels. Allows for custom styling and formatting that works cross-platform. |
661
772
  | `TickMarkLineComponent` | `LineComponent` | No | `SolidLine` | Component to render the tick marks. |
773
+ | `bandGridLinePlacement` | `end \| start \| middle \| edges` | No | `'edges'` | Placement of grid lines relative to each band. Options: start, middle, end, edges |
774
+ | `bandTickMarkPlacement` | `end \| start \| middle \| edges` | No | `'middle'` | Placement of tick marks relative to each band. Options: start, middle, end, edges |
662
775
  | `className` | `string` | No | `-` | Custom className for the axis. |
663
776
  | `classNames` | `{ root?: string; label?: string \| undefined; tickLabel?: string \| undefined; gridLine?: string \| undefined; line?: string \| undefined; tickMark?: string \| undefined; } \| undefined` | No | `-` | Custom classNames for the axis. |
664
777
  | `height` | `number` | No | `32 when no label is provided, 52 when a label is provided` | Height of the axis. This value is inclusive of the padding. |
@@ -568,6 +568,8 @@ function CustomTickLabelExample() {
568
568
  | `TickLabelComponent` | `AxisTickLabelComponent` | No | `DefaultAxisTickLabel` | Component to render tick labels. Allows for custom styling and formatting that works cross-platform. |
569
569
  | `TickMarkLineComponent` | `LineComponent` | No | `SolidLine` | Component to render the tick marks. |
570
570
  | `axisId` | `string` | No | `-` | The ID of the axis to render. Defaults to defaultAxisId if not specified. |
571
+ | `bandGridLinePlacement` | `end \| start \| middle \| edges` | No | `'edges'` | Placement of grid lines relative to each band. Options: start, middle, end, edges |
572
+ | `bandTickMarkPlacement` | `end \| start \| middle \| edges` | No | `'middle'` | Placement of tick marks relative to each band. Options: start, middle, end, edges |
571
573
  | `className` | `string` | No | `-` | Custom className for the axis. |
572
574
  | `classNames` | `{ root?: string; label?: string \| undefined; tickLabel?: string \| undefined; gridLine?: string \| undefined; line?: string \| undefined; tickMark?: string \| undefined; } \| undefined` | No | `-` | Custom classNames for the axis. |
573
575
  | `label` | `string` | No | `-` | Label text to display for the axis. |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coinbase/cds-mcp-server",
3
- "version": "8.36.2",
3
+ "version": "8.36.3",
4
4
  "description": "Coinbase Design System - MCP Server",
5
5
  "repository": {
6
6
  "type": "git",