2.6 KiB
2.6 KiB
UI Adapter Migration Playbook
Use this when moving UI primitives toward packages/ui hotswap-ready adapters.
Goal
App code should eventually depend on stable adapter contracts such as @toolctrl/ui/buttons, not directly on a specific library implementation. Migration happens category by category.
Migration Order
- Navigation and shell
- Buttons
- Dialogs and modals
- Tabs and tables
- Inputs
- Feedback
Adapter Levels
placeholder: category exists but exports no real adapter contract.available: package exposes stable metadata/contract for the current implementation.component-backed: package exports real reusable components or wrappers.migrated: app imports use the package adapter instead of app-local primitives.
Current status:
buttons:availablecontract forButtonandbuttonVariants.layout:availablecontract forShadcnSidebarLayoutandUiRegistry.navigation:availablecontract forAppSidebar,AdminSidebar,DocsSidebar,NavMain,NavSecondary,NavQuickLinks,NavActions, andSidebarPrimitives.- all other categories: placeholder registry.
Rules
- Start with metadata/contract exports before moving components.
- Keep adapter exports source-only and runtime-safe.
- Keep runtime components in
apps/web/app/until a migration phase explicitly moves imports. - Do not import app routes, data loaders, tenant context, admin context, or feature modules into
packages/ui. - Do not hide feature-specific behavior inside
packages/ui. - Keep shadcn/Radix as the current core default until a category-specific migration says otherwise.
- Treat Headless UI as legacy unless explicitly retained by a category decision.
Required Checks
For each category migration:
- Update
packages/ui/README.md. - Update the relevant
packages/ui/src/<category>.ts. - Update
docs/ui-inventory/components.json. - Add or update adapter contract tests.
- Keep app imports unchanged unless the phase explicitly migrates them.
Button Example
Current button adapter contract:
@toolctrl/ui/buttonsbuttonAdapterNamesbuttonAdapters- source:
apps/web/app/components/ui/button.tsx
This records stable intent without moving the current shadcn implementation yet.
Shell/Navigation Example
Current shell/navigation adapter contracts:
@toolctrl/ui/layoutlayoutAdapterNameslayoutAdapters@toolctrl/ui/navigationnavigationAdapterNamesnavigationAdapters
These records point agents to the current runtime sources in apps/web/app/ and are guarded by apps/web/app/application/ui/uiAdapters.test.ts plus the inventory tests.