# Migration playbook

## Classification tests

### Primitive test

Move to the primitive layer when the component:

- is independent of routes and application services;
- expresses one small visual or interaction responsibility;
- has stable native or upstream semantics;
- can be described through props, variants, slots and events;
- is useful in several patterns or applications.

### Pattern test

Move to the pattern layer when the component:

- composes package primitives;
- represents a recurring UI arrangement;
- accepts content and callbacks instead of importing business services;
- can be reused across products with theme changes only.

### Layout test

Move to a layout package when the component:

- arranges major page regions;
- can receive content through named slots;
- does not need to own route loading or CMS queries;
- has stable responsive behavior that is useful across sites.

### Application-owned test

Keep in the application when the component:

- imports domain services, route APIs, permissions or analytics;
- owns nonvisual workflows;
- is a one-off composition with no stable reusable view;
- embeds product copy or data assumptions that cannot be expressed as props.

## Controller/view split

For a mixed component:

```text
Before
UserMenu
├── reads session
├── calls logout API
├── checks permissions
└── renders menu

After
Application UserMenuController
├── reads session
├── calls logout API
├── checks permissions
└── renders @meyermedia/ui UserMenuView
```

The package view receives serializable data, slots and callbacks.

## Compatibility adapter

When call sites are numerous, keep the old application import temporarily:

```tsx
export { Button } from "@meyermedia/ui";
```

For renamed props, translate them in a thin adapter and mark it for removal. Do not duplicate visual implementation.

## Variant consolidation

Consolidate only when variants share behavior and structure.

Good consolidation:

```text
Button
variants: primary, secondary, outline, ghost, destructive
sizes: sm, md, lg, icon
```

Keep separate patterns when structure or semantics differ:

```text
Button
SplitButton
MenuButton
FloatingActionButton
```

Do not encode unrelated component families as dozens of boolean props.

## CSS migration

1. Identify global selectors used by the component.
2. Move reusable rules to semantic utilities or package component styles.
3. Convert brand values to semantic variables assigned by the application theme.
4. Preserve functional styles required by Radix positioning, portals or scroll areas.
5. Keep prose, Gutenberg, editor or vendor-content selectors in content adapter packages.
6. Delete old selectors only after repository search and rendered verification.

## Radix wrapper rules

- Import the exact primitive or unified Radix namespace internally.
- Export package-named parts.
- Preserve `asChild`, refs, native props, controlled and uncontrolled props.
- Style state through official data attributes.
- Do not expose the entire Radix namespace from the package barrel.
- Preserve portal, focus, dismissal and scroll-lock behavior.

## Motion rules

- Use CSS transitions for color, opacity and simple state changes.
- Use Motion for mount/unmount presence, layout, reordering, drag, swipe and coordinated sequences.
- Do not let Motion transforms overwrite required CSS positioning transforms; use wrappers when needed.
- Set global reduced motion to user preference and adapt large transform animations.

## Pull request strategy

Preferred sequence:

1. theme contract and package foundation;
2. foundational primitive family;
3. source application compatibility adapter;
4. application migration batch;
5. dead code removal after all consumers move.

Each pull request should state:

- source implementations reused;
- visual baselines checked;
- variants represented;
- intentional differences;
- commands run;
- remaining call sites;
- rollback method.

Do not combine a redesign, framework upgrade and extraction unless the user explicitly requested all three and verification can isolate failures.
