Skip to content

feat: add component-creation.md cursor rule#911

Closed
georgewrmarshall wants to merge 8 commits into
mainfrom
component-creation-cursor-rule
Closed

feat: add component-creation.md cursor rule#911
georgewrmarshall wants to merge 8 commits into
mainfrom
component-creation-cursor-rule

Conversation

@georgewrmarshall

@georgewrmarshall georgewrmarshall commented Feb 17, 2026

Copy link
Copy Markdown
Contributor

Description

Adds comprehensive cursor rule for component creation incorporating ADR-0003 (enum to string union migration), ADR-0004 (centralized types architecture), and platform-specific props patterns. Includes proof-of-concept BadgeStatus migration demonstrating the complete architectural approach.

Key insight: The rule focuses on what to do after running create-component scripts, since the generated templates don't yet implement these patterns. This ensures the rule stays relevant even as templates evolve.

What Changed

  1. Component Creation Cursor Rule: .cursor/rules/component-creation.md (600+ lines)

    • Platform-Specific Props Pattern: Added comprehensive guidance on handling cross-platform differences
    • Layered Architecture: Decision tree table showing what goes in shared vs platform layers
    • Reference-Based Approach: Points to templates instead of duplicating content
    • BadgeStatus Examples: Replaced Button examples with migrated BadgeStatus to show real implementation
    • Enhanced Verification: Updated checklist with platform-specific checks
  2. BadgeStatus Migration (Proof-of-Concept):

    • Shared Package: Created types/BadgeStatus/ with ADR-0003 pattern (const objects)
    • React Package: Re-exports shared types, extends with className and React-specific props
    • React Native Package: Re-exports shared types, extends with twClassName and React Native props
    • Type Cleanup: Removed old enum definitions from both platform packages
  3. Updated CLAUDE.md:

    • Added reference to component-creation.md rule
    • Added create-component:react-native command

Platform-Specific Props (Layered Architecture)

New guidance for handling cross-platform differences while maximizing consistency:

Concern Location Example
Visual variants Shared BadgeStatusStatus, ButtonVariant, ButtonSize
Design tokens Shared Colors, spacing, borders, radii
Behavioral states Shared isDisabled, isLoading, isSelected
Component structure Shared children, label, description
Platform interaction Platform onClick/onPress, onFocus/onBlur
Platform styling Platform className/twClassName
Platform base types Platform ComponentProps<'div'>/ViewProps
Platform constraints Platform htmlFor, testID, accessibility props

Philosophy: Use idiomatic platform APIs (onClick vs onPress) rather than unified abstractions. This maintains platform conventions and developer familiarity.

Key Architectural Patterns

ADR-0003 Pattern (Const Objects with String Unions):

// Before (generated template):
export enum BadgeStatusStatus {
  Active = 'active',
  Inactive = 'inactive',
}

// After (ADR-0003):
export const BadgeStatusStatus = {
  Active: 'active',
  Inactive: 'inactive',
} as const;
export type BadgeStatusStatus = 
  (typeof BadgeStatusStatus)[keyof typeof BadgeStatusStatus];

ADR-0004 Pattern (Centralized Types):

// Shared package - Design system concerns only
export type BadgeStatusPropsShared = {
  status: BadgeStatusStatus;
  hasBorder?: boolean;
  size?: BadgeStatusSize;
};

// React package - Platform-specific extension
export type BadgeStatusProps = 
  ComponentProps<'div'> &
  BadgeStatusPropsShared & {
    className?: string;
    style?: React.CSSProperties;
  };

// React Native package - Platform-specific extension
export type BadgeStatusProps = 
  BadgeStatusPropsShared &
  Omit<ViewProps, 'children'> & {
    twClassName?: string;
  };

Before/After Comparison (BadgeStatus)

Before (Duplicated Enums in Each Platform):

  • packages/design-system-react/src/types/index.ts:
    export enum BadgeStatusStatus { Active = 'active', ... }
    export enum BadgeStatusSize { Md = 'md', Lg = 'lg' }
  • packages/design-system-react-native/src/types/index.ts:
    export enum BadgeStatusStatus { Active = 'active', ... }
    export enum BadgeStatusSize { Md = 'md', Lg = 'lg' }
  • Total: ~40 lines duplicated

After (Shared Source + Platform Extensions):

  • packages/design-system-shared/src/types/BadgeStatus/:
    export const BadgeStatusStatus = { Active: 'active', ... } as const;
    export const BadgeStatusSize = { Md: 'md', Lg: 'lg' } as const;
    export type BadgeStatusPropsShared = { status, hasBorder, size };
  • Platform packages: Re-export shared, extend with className/twClassName
  • Result: Single source of truth, zero duplication

Why Reference-Based Instead of Duplicating Templates?

The rule is intentionally reference-based rather than duplicating template content:

Stays maintainable - Template updates don't require rule updates
Focuses on gaps - Guides patterns NOT in templates (ADR-0003/0004)
Post-generation workflow - What to do after scripts run
Explicit about template limitations - "Templates DO NOT include this pattern yet"

Testing Results

  • ✅ Build passes (yarn build)
  • ✅ Tests pass (yarn test)
  • ✅ Linting passes (yarn lint)
  • ✅ TypeScript compilation successful
  • ✅ No breaking changes to BadgeStatus component API
  • ✅ Import paths unchanged (consumers don't need updates)

Related issues

Relates to:

Manual testing steps

  1. Test Component Creation Workflow:

    • Start a new Claude Code or Cursor session
    • Ask: "Create a new Button component with variants"
    • Verify the AI agent:
      • Uses yarn create-component:react and yarn create-component:react-native
      • Moves types to @metamask/design-system-shared
      • Converts types to const objects + string unions (not enums)
      • Understands platform-specific props (className vs twClassName)
      • Creates identical shared APIs for React and React Native
  2. Verify BadgeStatus Migration:

    • Build passes: yarn build
    • Tests pass: yarn test
    • Lint passes: yarn lint
    • Import BadgeStatusStatus from both React and React Native packages
    • Verify types resolve correctly
    • Check component behavior unchanged
  3. Check Cross-Platform Consistency:

    • Compare BadgeStatusPropsShared exports
    • Verify platform packages have identical shared props
    • Confirm platform-specific differences only in extension layer

Screenshots/Recordings

Before

Component creation rule existed but was missing:

  • Platform-specific props guidance (onClick/onPress, className/twClassName)
  • Decision tree for shared vs platform concerns
  • Real migration example
  • BadgeStatus used old enum pattern with duplication

After

Component creation rule provides:

  • Platform-Specific Props Section: Layered architecture pattern
  • Decision Tree Table: Clear guidance on shared vs platform
  • BadgeStatus Examples: Real migrated component showing patterns
  • Verification Checklist: Platform-specific validation steps
  • Proof-of-Concept: BadgeStatus migrated using patterns

Pre-merge author checklist

  • I've followed MetaMask Contributor Docs
  • I've completed the PR template to the best of my ability
  • I've included tests if applicable (existing tests pass)
  • I've documented my code using JSDoc format if applicable
  • I've applied the right labels on the PR (see labeling guidelines). Not required for external contributors.

Pre-merge reviewer checklist

  • I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed).
  • I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.

🤖 Generated with Claude Code

Co-Authored-By: Claude noreply@anthropic.com


Note

Low Risk
Documentation-only changes (Cursor/agent rules and guides) with no runtime, API, or build logic modifications.

Overview
Adds new Cursor rule documentation for component work in the monorepo: a foundational architecture rule (component-architecture.md) covering ADR-0003/0004 patterns, layered shared-vs-platform props, and export conventions; plus workflows for component-creation.md (post-scaffold steps) and component-migration.md (extension/mobile → monorepo) and an internal refactor guide (component-enum-union-migration.md).

Updates existing docs to align with these workflows: clarifies Storybook story naming examples in component-documentation.md, streamlines and tightens the figma-integration.md Code Connect checklist/patterns, and updates CLAUDE.md + docs/ai-agents.md to reference the new rule files and include the create-component:react-native command.

Written by Cursor Bugbot for commit 61d44a3. This will update automatically on new commits. Configure here.

@github-actions

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@georgewrmarshall georgewrmarshall force-pushed the component-creation-cursor-rule branch from 648b2b5 to ec1fca7 Compare February 17, 2026 19:44
@github-actions

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@github-actions

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@github-actions

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@github-actions

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@@ -1,38 +1,22 @@
// Import shared type for extension

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved these changes into a separate PR #912

@georgewrmarshall georgewrmarshall force-pushed the component-creation-cursor-rule branch from a897c3f to 468efc2 Compare February 25, 2026 00:32
@github-actions

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

## Changes

### Critical Fixes
- Fix `interface` → `type` inconsistency in component-architecture.md
  - All shared props now use `type` not `interface` (aligns with ESLint rule)
  - Updated 6 instances across the file

- Replace duplicated BadgeStatus examples with @ references
  - Removed ~125 lines of duplicated code across files
  - Now references actual implementation as SOURCE OF TRUTH

### Code Duplication Reduction
- Consolidate Button type examples across 3 files
  - Reference BadgeStatus golden path instead of duplicating patterns

- Consolidate styling examples
  - Reference WalletHome.stories.tsx and styling.md instead of duplicating

### Clarity Improvements
- Add prominent BadgeStatus golden path callouts
  - Clearly marked as "THE proof-of-concept" and "SOURCE OF TRUTH"
  - Added in component-architecture.md, component-creation.md, component-enum-union-migration.md

- Add warnings to template references
  - ⚠️ callouts explaining templates are NOT ADR-compliant
  - 4 transformation steps required after scaffolding

- Enhance story naming examples
  - Added 5 concrete examples (variant → Variant, size → Size, etc.)

## Benefits
- Reduced maintenance: Code examples reference actual implementations
- Single source of truth: BadgeStatus is THE canonical example
- Consistency: All docs use same patterns
- Clarity: AI agents get non-contradictory guidance
- Up-to-date: References stay current automatically

## Files Modified
- .cursor/rules/component-architecture.md
- .cursor/rules/component-creation.md
- .cursor/rules/component-migration.md
- .cursor/rules/component-enum-union-migration.md
- .cursor/rules/component-documentation.md

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Comment thread .cursor/rules/component-creation.md

@georgewrmarshall georgewrmarshall left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some comments

Comment thread .cursor/rules/component-architecture.md Outdated
Comment on lines +9 to +10
- ADR-0003: String unions with const objects (no enums)
- ADR-0004: Centralized types in shared package

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why aren't we linking out to these?

Comment thread .cursor/rules/component-architecture.md Outdated

### Reference

[ADR-0003: Enum to String Union Migration](https://github.com/MetaMask/decisions/pull/127)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread .cursor/rules/component-architecture.md Outdated

### Reference

[ADR-0004: Centralized Types Architecture](https://github.com/MetaMask/decisions/pull/128)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


### Pattern

```tsx

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need these code examples or can we rely on either the ADR link or BadgeStatus component?

Comment thread .cursor/rules/component-architecture.md Outdated
Comment on lines +174 to +175
- **Shared interface**: `ComponentNamePropsShared` (with "Shared" suffix)
- **Platform interface**: `ComponentNameProps` (final exported type, no suffix)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

non-blocking: This is a good piece of information that is not documented anywhere that I'm aware. Should we create a template or script for this in @metamask/design-system-shared?

Comment thread .cursor/rules/component-creation.md Outdated

### Platform Types (Layered Architecture)

- [ ] Platform packages import shared type for extension

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- [ ] Platform packages import shared type for extension
- [ ] Platform packages import shared type


- [ADR-0003: Enum to String Union Migration](https://github.com/MetaMask/decisions/pull/127)
- [ADR-0004: Centralized Types Architecture](https://github.com/MetaMask/decisions/pull/128)
- [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs/)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again this rule is huge we need to cut it down


Common examples:

- BadgeStatus, AvatarAccount, Button (if using old enums)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BadgeStatus is the only one for now

Suggested change
- BadgeStatus, AvatarAccount, Button (if using old enums)
- BadgeStatus


### MetaMask Standards

- [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs/)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again some common issues, too many code examples that repeat existing golden path examples. Rule is too large 400 lines

Comment thread .cursor/rules/component-migration.md Outdated
Comment on lines +83 to +89
| Concern | Extension API | Mobile API | Decision |
| -------------- | -------------------- | ---------------------- | ------------------------- |
| Prop: variant | `variant?: string` | `type?: ButtonType` | Use `variant` |
| Prop: size | `size?: Size` | Not present | Add to both |
| Prop: disabled | `disabled?: boolean` | `isDisabled?: boolean` | Use `isDisabled` |
| Prop: onPress | `onClick` | `onPress` | Keep both (platform) |
| Styling | className | style object | Use className/twClassName |

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the initial migration we are going to accept component api inconsistencies for speed. We are then going to migrate them to have a shared API and consolidate and align later. See the migration process doc. Read this https://github.com/MetaMask/metamask-design-system/blob/296342a7bdab674db71e45f47506f8d35e7100e3/docs/component-migration-strategy.md

Address PR review feedback from georgewrmarshall:
- Add ADR links in Purpose section of component-architecture.md
- Update all ADR references from PR links to main branch document links
- Ensures documentation remains accessible even after PRs are merged

Changes:
- component-architecture.md: Added clickable ADR links in Purpose section (lines 9-10)
- Updated ADR-0003 reference from PR #127 to document link (line 58)
- Updated ADR-0004 reference from PR #128 to document link (line 166)
- Updated References section ADR links (lines 398-399)
- component-creation.md: Updated ADR links in MetaMask Standards section
- component-migration.md: Updated ADR links in Architecture Decision Records section
- component-enum-union-migration.md: Updated ADR links in Architecture Decision Records section

All ADR references now point to:
- https://github.com/MetaMask/decisions/blob/main/decisions/design-system/0003-enum-to-string-union-migration.md
- https://github.com/MetaMask/decisions/blob/main/decisions/design-system/0004-centralized-types-architecture.md

Related: #911 (review comments)
@github-actions

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

Following ai-agents.md principle: '200-400 lines per file (checklists, not novels)'

Changes:
- component-creation.md: 661 → 355 lines (46% reduction)
  - Replaced full code examples with references to BadgeStatus
  - Merged React/React Native steps (95% identical)
  - Condensed tutorials to actionable checklists

- component-migration.md: 440 → 332 lines (24% reduction)
  - Condensed audit phase tutorial to checklist
  - Referenced component-creation.md and styling.md for implementation
  - Collapsed scenarios to decision tree

- component-enum-union-migration.md: 403 → 218 lines (46% reduction)
  - Referenced component-architecture.md for all patterns
  - Removed duplicated type examples
  - Converted steps to workflow checklist

- figma-integration.md: 423 → 303 lines (28% reduction)
  - Combined six prop mapping examples into one comprehensive
  - Removed repetitive wizard steps
  - Streamlined critical rules to checklist

Total: 2,730 → 2,011 lines (26% reduction, 719 lines saved)

All files now closer to 200-400 line target while maintaining effectiveness
as AI agent guardrails using 'reference over duplication' principle.
Following ai-agents.md principle: '200-400 lines per file (checklists, not novels)'

Changes:
- component-architecture.md: 410 → 168 lines (59% reduction)

Condensation strategies:
- Removed ADR benefits/usage sections, linked to ADRs instead
- Condensed full three-layer example to minimal pattern + reference
- Merged decision table + quick rules - removed redundancy
- Kept BadgeStatus references prominent

Final status: ALL cursor rules files now within 200-400 line target:
  109 component-documentation.md
  168 component-architecture.md ✅
  224 component-enum-union-migration.md
  284 styling.md
  306 figma-integration.md
  342 component-migration.md
  357 component-creation.md
  1790 total (was 2730, saved 940 lines / 34% reduction)
@github-actions

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

georgewrmarshall and others added 2 commits February 25, 2026 17:16
Updated cursor rules to document correct export pattern:
- Component index.ts exports directly from @metamask/design-system-shared
- Platform src/types/index.ts should NOT re-export shared types
- Added verification checklist items for correct pattern

Files updated:
- component-enum-union-migration.md: Updated step 4, added step 5
- component-architecture.md: Added "Component Index Export Pattern" section
- component-creation.md: Added checklist item for export pattern

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Updated component creation documentation to prevent duplicate enum exports
that reduce test coverage:

- component-creation.md: Added critical warning that .types.ts files should
  ONLY import, never re-export enums. Enums exported from index.ts only.
- component-enum-union-migration.md: Clarified migration pattern with
  explicit examples showing .types.ts import-only pattern.
- Added anti-pattern sections showing the exact issue that caused BadgeCount
  coverage loss.

Pattern:
- .types.ts: Import only (prevents duplicate exports)
- index.ts: Single export location for enums (single source of truth)

This prevents Jest coverage failures from uncovered duplicate export paths.
@github-actions

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

Replaced "enum" terminology with "const object" throughout documentation
to accurately reflect ADR-0003 pattern and avoid confusion with TypeScript
enums.

Updated terminology:
- "enum exports" → "const object exports"
- "enum re-exports" → "const object re-exports"
- "design token enums" → "design token const objects"

Preserved "enum" only when referring to:
- TypeScript enums in anti-pattern examples
- File names (component-enum-union-migration.md)
- ADR-0003 title references
- Old TypeScript enums being migrated/removed

This clarifies that we're working with const objects (as const), not
TypeScript enums, making the documentation more precise and educational.
@github-actions

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@georgewrmarshall

Copy link
Copy Markdown
Contributor Author

Broken out and merged as separate PRs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant