Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 32 additions & 11 deletions .claude/skills/deprecate-cds-api/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ description: |
Also use when replacing a component or hook and sunsetting the old one. Always finish by running
`yarn nx run <project>:lint` on modified packages so `internal/deprecated-jsdoc-has-removal-version` passes.
allowed-tools: Read, Grep, Glob, StrReplace, Bash(yarn nx run:*)
argument-hint: '<SymbolName or path> — replacement — [@deprecationExpectedRemoval major e.g. v10] — [optional notes]'
argument-hint: '<SymbolName or path> — replacement — [@deprecationExpectedRemoval major e.g. v11] — [optional notes]'
---

# Deprecate CDS public API
Expand All @@ -20,7 +20,7 @@ Automate the standard CDS deprecation workflow for symbols exported from `packag

1. **What is being deprecated?** Component name, hook, prop, or other exported symbol.
2. **What should consumers use instead?** The replacement must be named in JSDoc and in docs `warning` text.
3. **Which major should `@deprecationExpectedRemoval` use?** (e.g. `v9`, `v10`.) **Ask the user to confirm** if they have not already stated it. If they want a default, **suggest** the next major from the relevant `package.json` (see Step 2) and confirm they accept it before editing.
3. **Which major should `@deprecationExpectedRemoval` use?** (e.g. `v11`.) **Ask the user to confirm** if they have not already stated it. If they want a default, **suggest** the earliest allowed removal major from Step 2 (current major + 2) and confirm they accept it before editing.

---

Expand Down Expand Up @@ -49,29 +49,50 @@ Use the **standard JSDoc tag `@deprecated`** (not `@deprecate`).
* …existing description if any…
*
* @deprecated <Clear guidance referencing the replacement>. This will be removed in a future major release.
* @deprecationExpectedRemoval v<NEXT_MAJOR>
* @deprecationExpectedRemoval v<M+2>
*/
```

Rules:

- The `@deprecated` line must end with exactly: `This will be removed in a future major release.` (same sentence as the rest of the deprecation message, as in existing CDS examples).
- `@deprecationExpectedRemoval` must match `v` + version (e.g. `v9` or `v9.0.0`; full semver is allowed by ESLint).
- `@deprecationExpectedRemoval` must match `v` + version (e.g. `v11` or `v11.0.0`; full semver is allowed by ESLint).
- **`v<M+2>`** is the earliest allowed removal major per Step 2 (full major undisturbed). Never use `v<M+1>` for a new deprecation.

The repo’s ESLint rule **`internal/deprecated-jsdoc-has-removal-version`** (`libs/eslint-plugin-internal`) enforces the prose ending and the presence of `@deprecationExpectedRemoval`; **lint must pass** after edits (see **Step 6**).

---

## Step 2 — Removal version for `@deprecationExpectedRemoval`

The tag must satisfy `@deprecationExpectedRemoval v…` as enforced by ESLint (e.g. `v10` or `v10.0.0`).
The tag must satisfy `@deprecationExpectedRemoval v…` as enforced by ESLint (e.g. `v11` or `v11.0.0`).

1. **Confirm with the user** which major **`N`** to use, unless they already specified it in **Inputs** (e.g. “remove in v10” → use `v10`).
2. **Default suggestion** when the user wants a recommendation: read the **`version`** field from the relevant `package.json` and set **`N = current major + 1`**.
- **`packages/web`**, **`packages/mobile`**, and **`packages/common`** always share the same semver — read **`version`** from any one of them (e.g. `8.60.0` → suggest **`v9`**).
3. After agreeing on **`N`**, use **`@deprecationExpectedRemoval v<N>`** everywhere for this deprecation (same **Step 3**).
### Policy — full major undisturbed (required)

Do **not** assume the default without checking—either the user names **`N`**, or they accept the suggested next-major after you show the current **`version`**.
Deprecated APIs must remain available for **one full major version undisturbed** before they may be removed.

That means: if you deprecate while shipping major **`M`**, the deprecation must still be present throughout **all of major `M+1`**, and the **earliest** allowed removal is major **`M+2`**.

Do **not** set `@deprecationExpectedRemoval` to the next major (`M+1`). Removal in `M+1` would give consumers **zero** undisturbed major in which the API is only deprecated (not yet removed).

Examples (read `version` from `packages/web`, `packages/mobile`, or `packages/common` — they share semver):

| Current package version | Current major `M` | Earliest `@deprecationExpectedRemoval` |
| ----------------------- | ----------------- | -------------------------------------- |
| `9.14.0` | `9` | **`v11`** (must survive all of v10) |
| `10.0.0` | `10` | **`v12`** (must survive all of v11) |

Never suggest or apply `v(M+1)` as the removal target for a newly introduced deprecation.

### Choosing `N`

1. **Confirm with the user** which major **`N`** to use, unless they already specified it in **Inputs** (e.g. “remove in v11” → use `v11`).
2. **Default suggestion** when the user wants a recommendation: read the **`version`** field from the relevant `package.json` and set **`N = current major + 2`** (the earliest allowed under the policy above).
- Example: `9.14.0` → suggest **`v11`**, not `v10`.
3. If the user asks for an earlier major than `M+2`, **refuse that default**, restate the full-major-undisturbed policy, and only proceed with a lower `N` if they explicitly override after that warning.
4. After agreeing on **`N`**, use **`@deprecationExpectedRemoval v<N>`** everywhere for this deprecation (same **Step 3**).

Do **not** assume the default without checking—either the user names **`N`**, or they accept the suggested **`M+2`** major after you show the current **`version`**.

---

Expand Down Expand Up @@ -123,7 +144,7 @@ Use the same `{replacement}` phrasing as in JSDoc. If the replacement is not a s

- [ ] Every **public export path** across packages that expose the symbol has been found (Step 0) and carries deprecation (implementation and re-exports as needed).
- [ ] `@deprecated` includes replacement guidance and the exact closing sentence about future major removal.
- [ ] **`@deprecationExpectedRemoval v<N>`** matches the **confirmed** removal major (Step 2), not an unverified default.
- [ ] **`@deprecationExpectedRemoval v<N>`** matches the **confirmed** removal major (Step 2), and **`N` is at least current major + 2** unless the user explicitly overrode the full-major-undisturbed policy after a warning.
- [ ] **Web + mobile** implementations and metadata (when applicable) are updated; nothing skipped because the symbol was “only” defined in common or another package.
- [ ] `warning` in metadata matches the replacement story: **this component is deprecated** for component docs, **this hook is deprecated** for hook docs (`apps/docs/docs/hooks/`).
- [ ] **`yarn nx run <project>:lint`** has been run for every touched project (**Step 6**) and passes.
Expand Down
2 changes: 2 additions & 0 deletions .claude/skills/research.deprecation-usage/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ description: |

Your objective is to provide information to user about the extent to which deprecated members of CDS are used in customer repositories. This information should be as accurate as possible as it will be used to inform decisions on whether or not it is safe to drop certain exports in a release or hold them for the next major version.

**Removal readiness policy:** a deprecated API must remain for **one full major version undisturbed** before removal. If it was deprecated during major `M`, it must survive all of `M+1`; the earliest removal major is `M+2` (see `@deprecationExpectedRemoval` and `.claude/skills/deprecate-cds-api/SKILL.md`).

Follow the

## 1 - Determining Research Scope
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -542,11 +542,11 @@ function DraggablePriceTarget() {
y={yPixel}
/>
<ChartText
disableRepositioning
color={color}
font="label1"
horizontalAlignment="left"
onDimensionsChange={(dimensions) => setTextDimensions(dimensions)}
repositionAxes="none"
verticalAlignment="middle"
x={drawingArea.x + padding + dragIconSize + iconGap + trendArrowIconSize}
y={yPixel + 1}
Expand Down
4 changes: 2 additions & 2 deletions apps/docs/docs/components/charts/Scrubber/_webExamples.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -792,12 +792,12 @@ function MatchupBeaconLabels() {
return (
<m.g animate={{ y }} initial={false} transition={transition}>
<ChartText
disableRepositioning
color={color}
dx={dx}
font="legal"
horizontalAlignment={horizontalAlignment}
onDimensionsChange={handleTeamLabelDimensionsChange}
repositionAxes="none"
verticalAlignment="bottom"
x={x}
y={transition ? 0 : y}
Expand All @@ -806,12 +806,12 @@ function MatchupBeaconLabels() {
{teamLabel}
</ChartText>
<ChartText
disableRepositioning
color={color}
dx={dx}
font="title3"
horizontalAlignment={horizontalAlignment}
onDimensionsChange={handlePercentageLabelDimensionsChange}
repositionAxes="none"
verticalAlignment="top"
x={x}
y={transition ? 0 : y}
Expand Down
28 changes: 26 additions & 2 deletions apps/docs/docs/components/charts/XAxis/_mobileExamples.mdx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## Basic Example
## Basic

The XAxis component provides a horizontal axis for charts with automatic tick generation and labeling.

Expand Down Expand Up @@ -235,7 +235,7 @@ For band scales, you can set the category padding to adjust the spacing between

## Axis Props

Properties related to the visual appearance of the XAxis are set on the component itself. This includes `position`, `showGrid`, `showLine`, `showTickMarks`, `size`, `tickInterval`, `ticks`, `tickLabelFormatter`, and `tickMarkSize`.
Properties related to the visual appearance of the XAxis are set on the component itself. This includes `position`, `showGrid`, `showLine`, `showTickMarks`, `size`, `tickInterval`, `ticks`, `tickLabelFormatter`, `tickLabelOverflow`, and `tickMarkSize`.

### Position

Expand Down Expand Up @@ -704,6 +704,30 @@ If no data is set for the axis, it will receive the regular number value of the
</CartesianChart>
```

### Tick Label Overflow

Use `tickLabelOverflow` to control how tick labels behave at the chart edges.

```jsx
<CartesianChart
height={250}
inset={0}
series={[
{
id: 'values',
data: [10, 22, 29, 45, 98, 45, 22],
},
]}
xAxis={{
data: ['1st', '2nd', '3rd', '4th', '5th', '6th', '7th'],
}}
yAxis={{ domain: { min: 0 } }}
>
<XAxis showLine showTickMarks tickLabelOverflow="fade" />
<Line seriesId="values" />
</CartesianChart>
```

### Label

You can add a label to the axis using the `label` prop.
Expand Down
56 changes: 54 additions & 2 deletions apps/docs/docs/components/charts/XAxis/_webExamples.mdx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## Basic Example
## Basics

The XAxis component provides a horizontal axis for charts with automatic tick generation and labeling.

Expand Down Expand Up @@ -235,7 +235,7 @@ For band scales, you can set the category padding to adjust the spacing between

## Axis Props

Properties related to the visual appearance of the XAxis are set on the component itself. This includes `position`, `showGrid`, `showLine`, `showTickMarks`, `size`, `tickInterval`, `ticks`, `tickLabelFormatter`, and `tickMarkSize`.
Properties related to the visual appearance of the XAxis are set on the component itself. This includes `position`, `showGrid`, `showLine`, `showTickMarks`, `size`, `tickInterval`, `ticks`, `tickLabelFormatter`, `tickLabelOverflow`, and `tickMarkSize`.

### Position

Expand Down Expand Up @@ -742,6 +742,58 @@ If no data is set for the axis, it will receive the regular number value of the
</CartesianChart>
```

### Tick Label Overflow

Use `tickLabelOverflow` to control how tick labels behave at the chart edges.

```jsx live
function TickLabelOverflowExample() {
const tickLabelOverflowModes = [
{ id: 'reposition', label: 'Reposition' },
{ id: 'fade', label: 'Fade' },
{ id: 'visible', label: 'Visible' },
];
const [selectedTickLabelOverflow, setSelectedTickLabelOverflow] = useState(
tickLabelOverflowModes[0],
);

return (
<VStack gap={2}>
<HStack alignItems="center" gap={2} justifyContent="flex-end">
<Text as="h3" font="headline">
Tick Label Overflow
</Text>
<SegmentedTabs
activeTab={selectedTickLabelOverflow}
onChange={setSelectedTickLabelOverflow}
tabs={tickLabelOverflowModes}
/>
</HStack>
<Box marginX={-3}>
<CartesianChart
height={250}
inset={0}
series={[
{
id: 'values',
data: [10, 22, 29, 45, 98, 45, 22],
color: 'var(--color-accentBoldBlue)',
},
]}
xAxis={{
data: ['1st', '2nd', '3rd', '4th', '5th', '6th', '7th'],
}}
yAxis={{ domain: { min: 0 } }}
>
<XAxis showLine showTickMarks tickLabelOverflow={selectedTickLabelOverflow.id} />
<Line seriesId="values" />
</CartesianChart>
</Box>
</VStack>
);
}
```

### Label

You can add a label to the axis using the `label` prop.
Expand Down
28 changes: 26 additions & 2 deletions apps/docs/docs/components/charts/YAxis/_mobileExamples.mdx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## Basic Example
## Basics

The YAxis component provides a vertical axis for charts with automatic tick generation and labeling.

Expand Down Expand Up @@ -113,7 +113,7 @@ You can pass in either an object (AxisBounds) with `min` and `max` properties (b

## Axis Props

Properties related to the visual appearance of the YAxis are set on the component itself. This includes `position`, `showGrid`, `showLine`, `showTickMarks`, `size`, `tickInterval`, `ticks`, `tickLabelFormatter`, and `tickMarkSize`.
Properties related to the visual appearance of the YAxis are set on the component itself. This includes `position`, `showGrid`, `showLine`, `showTickMarks`, `size`, `tickInterval`, `ticks`, `tickLabelFormatter`, `tickLabelOverflow`, and `tickMarkSize`.

### Position

Expand Down Expand Up @@ -444,6 +444,30 @@ You can customize the tick labels using the `tickLabelFormatter` prop.
</CartesianChart>
```

### Tick Label Overflow

Use `tickLabelOverflow` to control how tick labels behave at the chart edges.

```jsx
<CartesianChart
height={250}
inset={0}
series={[
{
id: 'values',
data: [10, 22, 29, 45, 98, 45, 22],
},
]}
xAxis={{
data: ['1st', '2nd', '3rd', '4th', '5th', '6th', '7th'],
}}
yAxis={{ domain: { min: 0 } }}
>
<YAxis showLine showTickMarks tickLabelOverflow="fade" width={64} />
<Line seriesId="values" />
</CartesianChart>
```

### Label

You can add a label to the axis using the `label` prop.
Expand Down
61 changes: 59 additions & 2 deletions apps/docs/docs/components/charts/YAxis/_webExamples.mdx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## Basic Example
## Basics

The YAxis component provides a vertical axis for charts with automatic tick generation and labeling.

Expand Down Expand Up @@ -107,7 +107,7 @@ You can pass in either an object (AxisBounds) with `min` and `max` properties (b

## Axis Props

Properties related to the visual appearance of the YAxis are set on the component itself. This includes `position`, `showGrid`, `showLine`, `showTickMarks`, `size`, `tickInterval`, `ticks`, `tickLabelFormatter`, and `tickMarkSize`.
Properties related to the visual appearance of the YAxis are set on the component itself. This includes `position`, `showGrid`, `showLine`, `showTickMarks`, `size`, `tickInterval`, `ticks`, `tickLabelFormatter`, `tickLabelOverflow`, and `tickMarkSize`.

### Position

Expand Down Expand Up @@ -430,6 +430,63 @@ You can customize the tick labels using the `tickLabelFormatter` prop.
</CartesianChart>
```

### Tick Label Overflow

Use `tickLabelOverflow` to control how tick labels behave at the chart edges.

```jsx live
function TickLabelOverflowExample() {
const tickLabelOverflowModes = [
{ id: 'reposition', label: 'Reposition' },
{ id: 'fade', label: 'Fade' },
{ id: 'visible', label: 'Visible' },
];
const [selectedTickLabelOverflow, setSelectedTickLabelOverflow] = useState(
tickLabelOverflowModes[0],
);

return (
<VStack gap={2}>
<HStack alignItems="center" gap={2} justifyContent="flex-end">
<Text as="h3" font="headline">
Tick Label Overflow
</Text>
<SegmentedTabs
activeTab={selectedTickLabelOverflow}
onChange={setSelectedTickLabelOverflow}
tabs={tickLabelOverflowModes}
/>
</HStack>
<Box marginX={-3}>
<CartesianChart
height={250}
inset={0}
series={[
{
id: 'values',
data: [10, 22, 29, 45, 98, 45, 22],
color: 'var(--color-accentBoldBlue)',
},
]}
xAxis={{
data: ['1st', '2nd', '3rd', '4th', '5th', '6th', '7th'],
}}
yAxis={{ domain: { min: 0 } }}
>
<YAxis
showLine
showTickMarks
tickLabelOverflow={selectedTickLabelOverflow.id}
width={64}
/>
<Line seriesId="values" />
</CartesianChart>
</Box>
</VStack>
);
}
```

### Label

You can add a label to the axis using the `label` prop.
Expand Down
4 changes: 4 additions & 0 deletions packages/common/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ All notable changes to this project will be documented in this file.

<!-- template-start -->

## 9.14.0 ((8/11/2026, 11:48 AM PST))

This is an artificial version bump with no new change.

## 9.13.0 ((8/11/2026, 09:52 AM PST))

This is an artificial version bump with no new change.
Expand Down
2 changes: 1 addition & 1 deletion packages/common/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@coinbase/cds-common",
"version": "9.13.0",
"version": "9.14.0",
"description": "Coinbase Design System - Common",
"repository": {
"type": "git",
Expand Down
Loading
Loading