Skip to content
Open
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
421 changes: 421 additions & 0 deletions .claude/skills/cds-rn-to-compose/SKILL.md

Large diffs are not rendered by default.

23 changes: 23 additions & 0 deletions .claude/skills/cds-rn-to-compose/evals/evals.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"skill_name": "cds-rn-to-compose",
"evals": [
{
"id": 1,
"prompt": "Port the CDS Chip component from packages/mobile to packages/cds-android as a full Jetpack Compose implementation. Match mobile variants and states, add tests and a gallery section in android-app.",
"expected_output": "Discovery artifact, public Chip composable with modifier-first API, CdsTheme tokens, interaction wiring if pressable, Robolectric tests, gallery, docs, passing cds-android:test and build",
"files": []
},
{
"id": 2,
"prompt": "Audit the Android Button port in packages/cds-android against packages/mobile/src/buttons/Button.tsx. Tell me what's missing or wrong and whether we're ready to ship.",
"expected_output": "Structured audit report using audit checklist: API parity table, deprecated props omitted, interaction/semantics/tests/docs gaps, verdict",
"files": []
},
{
"id": 3,
"prompt": "I'm adding a new ToggleRow to mobile — should we also add it to cds-android now? Walk me through what the Android port would need without writing all the code yet.",
"expected_output": "Discovery-style plan: source files to read, interaction analysis, API sketch, token mapping, test plan, explicit out-of-scope items, no Compose Styles API",
"files": []
}
]
}
155 changes: 155 additions & 0 deletions .claude/skills/cds-rn-to-compose/references/audit-checklist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
# Android port audit checklist

Use when reviewing an existing `packages/cds-android` component against its `packages/mobile` source. Score each item: **Pass**, **Gap**, or **N/A**.

## 1. Discovery & scope

- [ ] RN source, stories, tests, and common tokens were consulted
- [ ] Deprecated RN props are **not** present on the Android API
- [ ] `useComponentConfig`, haptics, debounce, `wrapperStyles` were not ported
- [ ] Out-of-scope items are documented (not silently wrong)

## 2. API shape (Compose + CDS)

- [ ] `@Composable` returns `Unit`, PascalCase name
- [ ] `modifier: Modifier = Modifier` is first optional parameter
- [ ] Modifier applied exactly once on outermost layout node
- [ ] Parameter order: required → modifier → optional → composable slots
- [ ] Defaults live in the function signature
- [ ] Only intentional symbols are `public` (explicit API mode)
- [ ] Style resolvers, resolved types (`*Colors`, `*Metrics`), and assembly composables are `internal`
- [ ] No symbols widened to `public` only for tests or the demo app
- [ ] Demo app does not require widening internal APIs

Reference: `jetpack-best-practices` skill, `packages/cds-android/AGENTS.md`

## 3. Parity matrix

Build a table:

| RN prop / behavior | Android equivalent | Match? | Notes |
|------------------|-------------------|--------|-------|

Check variants, sizes, defaults, loading, disabled, transparent modes, icon slots, truncation, accessibility.

**Common gaps:**

- Missing variant or size enum value
- RN `block` incorrectly modeled as prop instead of modifier docs
- `IconName` instead of composable slots
- Loading still clickable
- Label lost in loading semantics

## 4. Theming & visuals

- [ ] Colors from `CdsTheme.colors.*` (resolved via `LocalCdsTheme`, not component props)
- [ ] Spacing from `CdsTheme.space.*`
- [ ] Typography from `CdsTheme.typography.*`
- [ ] Border radius from `CdsTheme.borderRadius.*`
- [ ] Components do not accept raw color/spacing props where RN used `useTheme()` — tokens come from CompositionLocal
- [ ] Tests/gallery wrap content in `CdsThemeProvider`
- [ ] Token values traceable to `@coinbase/cds-common` source (comment or doc)
- [ ] Transparent / inverse / semantic variants match token intent
- [ ] **No** Compose Styles API usage

## 5. Styling override model

- [ ] Opinionated defaults implemented in component
- [ ] Callers can override layout via `modifier` (padding, width, test tags)
- [ ] No RN-style `style` / `styles` props unless explicitly required by product
- [ ] Style logic extracted to testable `*Style.kt` resolvers where non-trivial

## 6. Interactions

- [ ] Interaction types identified (press, hover, focus, drag, toggle, long-press)
- [ ] Each produced interaction uses the correct Compose modifier
- [ ] `CdsInteractionDefaults.indication()` used for CDS feedback (not ad-hoc alpha hacks)
- [ ] Optional `interactionSource: MutableInteractionSource` hoisted when customers need observation
- [ ] Same `InteractionSource` passed to gesture + indication
- [ ] Disabled: `DisabledAlpha` + gestures blocked
- [ ] Loading: gestures blocked + correct semantics

If indication supports hover/focus but modifiers are missing, flag as **Gap**.

Docs: `packages/cds-android/docs/interaction.md`

## 7. Accessibility

- [ ] Correct `Role` in semantics
- [ ] `contentDescription` for icon-only or primary label
- [ ] `disabled()` when not interactive
- [ ] Loading: progress semantics + label retained
- [ ] `mergeDescendants` only when appropriate

Reference: https://developer.android.com/develop/ui/compose/accessibility

## 8. Tests

- [ ] `yarn nx run cds-android:test` passes
- [ ] Pure resolver tests for colors/metrics/state priority
- [ ] Robolectric + Compose UI tests for behavior (click, disabled, semantics)
- [ ] Caller `Modifier.testTag` queryable via `onNodeWithTag` (RN `testID` parity)
- [ ] Interaction event tests when `MutableInteractionSource` is hoisted
- [ ] Tests focus on regressions, not exhaustive variant grids
- [ ] No tests that only assert framework defaults

Reference: `references/ui-testing.md`, [Maestro Jetpack Compose](https://docs.maestro.dev/get-started/supported-platform/android/jetpack)

## 8b. UI testing hooks

- [ ] No dedicated `testID` prop — tags via `modifier.testTag` on root
- [ ] Maestro selector priority documented: text → description → id
- [ ] `apps/android-app` enables `testTagsAsResourceId` at activity root
- [ ] Gallery uses stable `gallery-*` tags on navigation and representative states
- [ ] `mergeDescendants` does not block intended tag placement

**Anti-patterns:**

- Only headless theme tests, no component behavior tests
- 20 tests duplicating the same assertion per variant
- No tests for disabled/loading/click paths

## 9. Demo & documentation

- [ ] Gallery section covers variants, states, sizes, edge cases
- [ ] KDoc on public composable and types matches API (no per-component `docs/*.md`)
- [ ] `CHANGELOG.md` mentions public API changes
- [ ] `AGENTS.md` public surface list accurate
- [ ] `interactionSource` documented if hoisted

## 10. Build & boundaries

- [ ] `yarn nx run cds-android:build` passes
- [ ] No `@coinbase/cds-common` imports
- [ ] No Yarn/npm deps added to cds-android
- [ ] Gradle version unchanged unless releasing

## 11. Skill maintenance

- [ ] `references/learnings.md` was read at audit start
- [ ] New generalizable learnings appended to `learnings.md` (if any)
- [ ] Repeatable patterns promoted to `SKILL.md` or reference files (if warranted)
- [ ] Reference implementation example still accurate

## Audit report template

```markdown
# <Component> port audit

**Verdict:** Ready / Needs work / Blocked

## Critical gaps
1.

## API parity
| RN | Android | Status |

## Interactions
...

## Tests
...

## Recommendations (ordered)
1.
```
73 changes: 73 additions & 0 deletions .claude/skills/cds-rn-to-compose/references/compose-docs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Official Jetpack Compose documentation

Primary sources of truth for Compose patterns used in CDS Android ports. Prefer these over blog posts or outdated samples.

## Core concepts

| Topic | URL |
|-------|-----|
| Compose mental model | https://developer.android.com/develop/ui/compose/mental-model |
| Modifiers | https://developer.android.com/develop/ui/compose/modifiers |
| State | https://developer.android.com/develop/ui/compose/state |
| Side-effects | https://developer.android.com/develop/ui/compose/side-effects |

## API design

| Topic | URL |
|-------|-----|
| Compose API guidelines (AOSP) | https://android.googlesource.com/platform/frameworks/support/+/androidx-main/compose/docs/compose-api-guidelines.md |
| Component API guidelines | https://android.googlesource.com/platform/frameworks/support/+/androidx-main/compose/docs/compose-component-api-guidelines.md |
| List of Compose modifiers | https://developer.android.com/develop/ui/compose/modifiers-list |

## Interaction & input

| Topic | URL |
|-------|-----|
| Touch input / clickable | https://developer.android.com/develop/ui/compose/touch-input/pointer-input/tap-and-press |
| Focus | https://developer.android.com/develop/ui/compose/touch-input/focus |
| InteractionSource | https://developer.android.com/reference/kotlin/androidx/compose/foundation/interaction/InteractionSource |
| Indication | https://developer.android.com/reference/kotlin/androidx/compose/foundation/Indication |

## Layout & theming

| Topic | URL |
|-------|-----|
| Layout basics | https://developer.android.com/develop/ui/compose/layout/basics |
| Material theming (concepts; CDS uses CdsTheme) | https://developer.android.com/develop/ui/compose/designsystems/material |
| Custom design systems | https://developer.android.com/develop/ui/compose/designsystems |

## Accessibility

| Topic | URL |
|-------|-----|
| Accessibility overview | https://developer.android.com/develop/ui/compose/accessibility |
| Semantics | https://developer.android.com/reference/kotlin/androidx/compose/ui/semantics/SemanticsPropertyReceiver |

## Testing

| Topic | URL |
|-------|-----|
| Testing overview | https://developer.android.com/develop/ui/compose/testing |
| Compose UI testing cheatsheet | https://developer.android.com/develop/ui/compose/testing-cheatsheet |
| Interoperability (Robolectric) | https://developer.android.com/develop/ui/compose/testing#robolectric |

## Kotlin library authoring

| Topic | URL |
|-------|-----|
| Explicit API mode | https://kotlinlang.org/docs/whatsnew14.html#explicit-api-mode-for-library-authors |

## CDS-specific (repo)

| Topic | Path |
|-------|------|
| Android package rules | `packages/cds-android/AGENTS.md` |
| Theme design | `packages/cds-android/src/main/java/com/coinbase/cds/theme/README.md` |
| Interaction docs | `packages/cds-android/docs/interaction.md` |
| Jetpack best practices skill | `.claude/skills/jetpack-best-practices/SKILL.md` |

## Intentionally not used (yet)

| Topic | URL | Note |
|-------|-----|------|
| Compose Styles API | https://developer.android.com/develop/ui/compose/designsystems/styles | Alpha — CDS uses `*Style.kt` resolvers instead |
145 changes: 145 additions & 0 deletions .claude/skills/cds-rn-to-compose/references/discovery-template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
# Discovery: `<ComponentName>` RN → Compose

Copy this template into a PR description or working note. Fill every section before writing Kotlin.

## Source inventory

| Artifact | Path | Reviewed |
|----------|------|----------|
| RN implementation | `packages/mobile/src/.../<Component>.tsx` | [ ] |
| Common types | `packages/common/src/types/...` | [ ] |
| Tokens | `packages/common/src/tokens/...` | [ ] |
| Stories | `packages/mobile/src/**/__stories__/<Component>.stories.tsx` | [ ] |
| RN tests | `packages/mobile/src/**/__tests__/<Component>.test.tsx` | [ ] |
| iOS (if any) | `packages/cds-ios/Sources/Components/<Component>.swift` | [ ] |
| Existing Android | `packages/cds-android/...` | [ ] |

## Deprecated API (do not port)

List every `@deprecated` prop, variant, or type found in mobile/common:

| Symbol | Deprecation reason | Android action |
|--------|-------------------|----------------|
| | | Skip |

## Public API proposal

### Composable signature (draft)

```kotlin
@Composable
fun ComponentName(
// required
modifier: Modifier = Modifier,
// ...
)
```

### Props mapping

| RN prop | Compose equivalent | Port? | Notes |
|---------|-------------------|-------|-------|
| `style` | `modifier` | Partial | Layout only |
| `block` | — | No | Caller `fillMaxWidth()` |
| | | | |

### Variants / sizes / enums

| RN | Kotlin type | Default |
|----|-------------|---------|
| | | |

## Layout & slots

- **Intrinsic size behavior:**
- **Icon/content slots:** `@Composable (tint: Color, size: Dp) -> Unit` or content lambda?
- **Caller-controlled layout:** document `Modifier` patterns (padding, fillMaxWidth, weight)

## Interaction analysis

| Interaction | Needed? | RN mechanism | Compose modifier | Customer observable? |
|-------------|---------|--------------|------------------|---------------------|
| Press | | `Pressable` | `clickable` | `MutableInteractionSource` |
| Hover | | `Interactable` | `hoverable` | |
| Focus | | focus styles | `focusable` | |
| Long press | | | `combinedClickable` | |
| Drag | | | | |
| Toggle | | | | |

**Indication:** `CdsInteractionDefaults.indication()` or `indication(shape)`?

**Disabled treatment:** `CdsInteractionDefaults.DisabledAlpha` + block gestures when disabled/loading

## States

| State | Visual | Behavioral | Semantics |
|-------|--------|------------|-----------|
| enabled | | | |
| disabled | | block input | `disabled()` |
| loading | | block input | progress + label |

## Test IDs

| RN | Android CDS | Notes |
|----|-------------|-------|
| `testID` on root | `modifier = Modifier.testTag("…")` | No dedicated prop |
| Maestro `id:` | same tag + app `testTagsAsResourceId` | See `references/ui-testing.md` |

**Maestro selector plan:** text match / `description` / `id` for each critical flow?

**Gallery tags:** stable `gallery-*` ids for visreg anchors?

## Token mapping

| Visual property | cds-common token | CdsTheme accessor | Delivery |
|-----------------|------------------|-------------------|----------|
| Background | | `CdsTheme.colors.*` | `LocalCdsTheme` via `CdsThemeProvider` |
| Foreground | | | |
| Padding | | `CdsTheme.space.*` | |
| Typography | | `CdsTheme.typography.*` | |
| Radius | | `CdsTheme.borderRadius.*` | |

**Token gaps:** (values missing from Android theme — file follow-up)

## Explicitly out of scope

- [ ] `useComponentConfig`
- [ ] Haptics / debounce / `flush`
- [ ] `wrapperStyles` / granular `styles` object
- [ ] Compose Styles API (alpha)
- [ ] Deprecated props listed above

## Reuse

- [ ] `CdsInteractionDefaults`
- [ ] Internal `Text` or other CDS components
- [ ] Shared style resolvers pattern (`*Style.kt`)

## Test plan

| Test | Type | Priority |
|------|------|----------|
| Style resolver token mapping | JUnit pure | High |
| onClick / callback | Robolectric | High |
| Disabled blocks interaction | Robolectric | High |
| Loading semantics | Robolectric | High |
| InteractionSource press events | Robolectric | If hoisted |
| Icon slot tint/size | Robolectric | If slots |

## Demo & docs

- Gallery section: `apps/android-app/.../<Component>GallerySection.kt`
- KDoc on public composable and types (no per-component `docs/*.md`)
- CHANGELOG entry

## Open questions

-

## Skill feedback (Phase 8)

After the port, note anything that should be added to `references/learnings.md` or promoted into the skill:

| Learning | Generalizable? | Target file |
|----------|----------------|-------------|
| | Yes / No / Pending | `learnings.md` / `SKILL.md` / mapping / audit |
Loading
Loading