Migration
V2 to V3
Upgrade to the V3 npm runtime package for centralized semver updates, or move selected components to the source registry when you need local ownership. Both routes can coexist during an incremental migration.
Npm package upgrade
Keep supported package imports and move the application to the V3 runtime package.
pnpm add poyraz-ui@3Own the source
Follow the incremental sequence below for components that need source-level control.
pnpm dlx shadcn@latest add @poyraz/buttonIncremental sequence
1. Foundation
Install the generated theme, utilities and shared recipes before visual components.
pnpm dlx shadcn@latest add @poyraz/poyraz-theme @poyraz/poyraz-utils @poyraz/poyraz-recipes2. Primitives
Move Button, Input and Card separately and compare dimensions before changing variants.
pnpm dlx shadcn@latest add @poyraz/button @poyraz/input @poyraz/card3. Interactive components
Move one Radix family at a time, then verify keyboard and focus behavior.
pnpm dlx shadcn@latest add @poyraz/dialog @poyraz/select @poyraz/dropdown-menu @poyraz/tabs4. Organisms and blocks
Install composite layouts only after their child component migrations are stable.
pnpm dlx shadcn@latest add @poyraz/navbar @poyraz/sidebar @poyraz/footer @poyraz/dashboard-shell-blockComponent mapping
This mapping is only required for the source-ownership route. Install the registry item first, then replace that component's package import with the local target.
| Layer | V2 symbols | V3 item | Local import |
|---|---|---|---|
| Atoms | poyraz-ui/atoms: Avatar* | @poyraz/avatar | @/components/ui/atoms/avatar |
| Atoms | poyraz-ui/atoms: Badge | @poyraz/badge | @/components/ui/atoms/badge |
| Atoms | poyraz-ui/atoms: Button, buttonVariants | @poyraz/button | @/components/ui/atoms/button |
| Atoms | poyraz-ui/atoms: Card* | @poyraz/card | @/components/ui/atoms/card |
| Atoms | poyraz-ui/atoms: BasicContentCard, GlassCard and card compositions | @poyraz/card-variants | @/components/ui/atoms/card-variants |
| Atoms | poyraz-ui/atoms: Checkbox | @poyraz/checkbox | @/components/ui/atoms/checkbox |
| Atoms | poyraz-ui/atoms: Input, InputGroup* | @poyraz/input | @/components/ui/atoms/input |
| Atoms | poyraz-ui/atoms: NumberInput, MaskedInput and field helpers | @poyraz/form-fields | @/components/ui/atoms/form-fields |
| Atoms | poyraz-ui/atoms: Label | @poyraz/label | @/components/ui/atoms/label |
| Atoms | poyraz-ui/atoms: Logo | @poyraz/logo | @/components/ui/atoms/logo |
| Atoms | poyraz-ui/atoms: RadioGroup* | @poyraz/radio-group | @/components/ui/atoms/radio-group |
| Atoms | poyraz-ui/atoms: ScrollArea | @poyraz/scroll-area | @/components/ui/atoms/scroll-area |
| Atoms | poyraz-ui/atoms: Separator | @poyraz/separator | @/components/ui/atoms/separator |
| Atoms | poyraz-ui/atoms: Skeleton | @poyraz/skeleton | @/components/ui/atoms/skeleton |
| Atoms | poyraz-ui/atoms: Switch | @poyraz/switch | @/components/ui/atoms/switch |
| Atoms | poyraz-ui/atoms: Textarea | @poyraz/textarea | @/components/ui/atoms/textarea |
| Atoms | poyraz-ui/atoms: Typography, TextEffect | @poyraz/typography | @/components/ui/atoms/typography |
| Atoms | poyraz-ui/atoms: Pattern* | @poyraz/bg-pattern | @/components/ui/atoms/bg-pattern |
| Molecules | poyraz-ui/molecules: Accordion* | @poyraz/accordion | @/components/ui/molecules/accordion |
| Molecules | poyraz-ui/molecules: Alert* | @poyraz/alert | @/components/ui/molecules/alert |
| Molecules | poyraz-ui/molecules: Autocomplete | @poyraz/autocomplete | @/components/ui/molecules/autocomplete |
| Molecules | poyraz-ui/molecules: Breadcrumb* | @poyraz/breadcrumb | @/components/ui/molecules/breadcrumb |
| Molecules | poyraz-ui/molecules: Calendar | @poyraz/calendar | @/components/ui/molecules/calendar |
| Molecules | poyraz-ui/molecules: CommandPalette* | @poyraz/command-palette | @/components/ui/molecules/command-palette |
| Molecules | poyraz-ui/molecules: DatePicker | @poyraz/date-picker | @/components/ui/molecules/date-picker |
| Molecules | poyraz-ui/molecules: Dialog* | @poyraz/dialog | @/components/ui/molecules/dialog |
| Molecules | poyraz-ui/molecules: Drawer* | @poyraz/drawer | @/components/ui/molecules/drawer |
| Molecules | poyraz-ui/molecules: DropdownMenu* | @poyraz/dropdown-menu | @/components/ui/molecules/dropdown-menu |
| Molecules | poyraz-ui/molecules: Form* | @poyraz/form | @/components/ui/molecules/form |
| Molecules | poyraz-ui/molecules: HoverCard* | @poyraz/hover-card | @/components/ui/molecules/hover-card |
| Molecules | poyraz-ui/molecules: Mermaid | @poyraz/mermaid | @/components/ui/molecules/mermaid |
| Molecules | poyraz-ui/molecules: Modal* | @poyraz/modal | @/components/ui/molecules/modal |
| Molecules | poyraz-ui/molecules: Pagination* | @poyraz/pagination | @/components/ui/molecules/pagination |
| Molecules | poyraz-ui/molecules: Popover* | @poyraz/popover | @/components/ui/molecules/popover |
| Molecules | poyraz-ui/molecules: Select* | @poyraz/select | @/components/ui/molecules/select |
| Molecules | poyraz-ui/molecules: Sheet* | @poyraz/sheet | @/components/ui/molecules/sheet |
| Molecules | poyraz-ui/molecules: Tabs* | @poyraz/tabs | @/components/ui/molecules/tabs |
| Molecules | poyraz-ui/molecules: Toaster, toast | @poyraz/sonner | @/components/ui/molecules/sonner |
| Molecules | poyraz-ui/molecules: Tooltip* | @poyraz/tooltip | @/components/ui/molecules/tooltip |
| Blocks | poyraz-ui/molecules: ArticleCard | @poyraz/article-card | @/components/ui/blocks/card-templates/article-card |
| Blocks | poyraz-ui/molecules: ImageCard | @poyraz/image-card | @/components/ui/blocks/card-templates/image-card |
| Blocks | poyraz-ui/molecules: NewsCard | @poyraz/news-card | @/components/ui/blocks/card-templates/news-card |
| Blocks | poyraz-ui/molecules: StatsCard | @poyraz/stats-card | @/components/ui/blocks/card-templates/stats-card |
| Blocks | poyraz-ui/molecules: TestimonialCard | @poyraz/testimonial-card | @/components/ui/blocks/card-templates/testimonial-card |
| Blocks | poyraz-ui/molecules: PricingCard | @poyraz/pricing-card | @/components/ui/blocks/card-templates/pricing-card |
| Blocks | poyraz-ui/molecules: ProductCard | @poyraz/product-card | @/components/ui/blocks/card-templates/product-card |
| Organisms | poyraz-ui/organisms: AnnouncementBar | @poyraz/announcement-bar | @/components/ui/organisms/announcement-bar |
| Organisms | poyraz-ui/organisms: DataTable* | @poyraz/data-table | @/components/ui/organisms/data-table |
| Organisms | poyraz-ui/organisms: DataTableCore | @poyraz/data-table-core | @/components/ui/organisms/data-table-core |
| Organisms | poyraz-ui/organisms: Footer* | @poyraz/footer | @/components/ui/organisms/footer |
| Organisms | poyraz-ui/organisms: FooterNewsletter | @poyraz/footer-newsletter | @/components/ui/organisms/footer-newsletter |
| Organisms | poyraz-ui/organisms: Navbar* | @poyraz/navbar | @/components/ui/organisms/navbar |
| Organisms | poyraz-ui/organisms: Sidebar* | @poyraz/sidebar | @/components/ui/organisms/sidebar |
Prop mapping
| Component | V2 | V3 | Action |
|---|---|---|---|
| All | className | className | Preserved; re-apply overrides after visual comparison. |
| All forwardRef components | ref | ref | Preserved. |
| Button | asChild | asChild | Preserved; disabled links now use aria-disabled. |
| Button | loading | loading | Preserved; V3 keeps an accessible name and blocks interaction. |
| Button | variant, size | variant, size, radius, effect, fillDirection, swapTarget | Existing names compile; review changed dimensions and opt into new effects. |
| Card | variant | variant, radius | Legacy variants remain; V3 default radius is xl. |
| Badge | variant | variant, size, radius | Existing variants remain; root element is now span rather than div. |
| Input/Textarea | native props | native props plus size/radius/invalid | Preserved; use aria-invalid for validation state. |
| Dialog/Sheet/Modal | open, defaultOpen, onOpenChange | same controlled contract | Preserved; re-test focus return and portal theme inheritance. |
| Select/Tabs/Accordion | value, defaultValue, onValueChange | same controlled contract | Preserved; re-test keyboard behavior. |
| Navbar/Sidebar | layout props | composable parts plus container-responsive props | Migrate composition manually; codemod only changes safe imports. |
| Theme | ThemeProvider themes object | CSS variables on :root/.dark/[data-poyraz-theme] | Remove runtime theme objects after CSS parity is verified. |
Variant changes
| Component | V2 | V3 | Action |
|---|---|---|---|
| Button | default|secondary|outline|destructive|ghost|link | same names | Visual treatment and control heights changed; snapshot each use. |
| Button | size=default (32px) | size=sm (32px) | Use sm to preserve approximate old height; V3 default is 40px. |
| Button | size=sm (28px) | size=xs (28px) | Use xs for approximate parity. |
| Button | size=lg (36px) | size=default (40px) or lg (44px) | No exact alias; choose by layout. |
| Card | default|bordered|elevated|highlight|ghost|interactive | same names | Compatibility names remain but V3 removes directional hover movement. |
| Badge | default|secondary|outline|destructive | same plus glass|info|success|warning | Existing names remain; V3 defaults to full radius. |
| Typography | legacy visual variants | semantic typography variants and text effects | Review heading level separately from visual variant. |
Token mapping
| V2 token | V3 token | Status |
|---|---|---|
| --poyraz-background | --poyraz-background | preserved |
| --poyraz-foreground | --poyraz-foreground | preserved |
| --poyraz-primary* | --poyraz-primary* | preserved, values redesigned |
| --poyraz-secondary* | --poyraz-secondary* | preserved, semantic surface |
| --poyraz-muted* | --poyraz-muted* | preserved |
| --poyraz-accent* | --poyraz-accent* | preserved |
| --poyraz-destructive* | --poyraz-destructive* | preserved |
| --poyraz-border / --poyraz-border-strong | same names | preserved |
| --poyraz-input | --poyraz-input | preserved |
| --poyraz-ring | --poyraz-ring | preserved |
| --poyraz-overlay* | --poyraz-overlay* | preserved, backdrop policy added |
| --poyraz-surface-50/100/200 | same aliases; prefer --poyraz-surface, -subtle, -raised, -elevated | compatibility alias |
| --poyraz-info/success/warning* | same semantic names | preserved, independent status palettes |
| --font-sans | --poyraz-font-primary | Tailwind alias remains |
| --font-secondary | --poyraz-font-secondary | Tailwind alias remains |
| custom hardcoded glass colors | --poyraz-glass-* | replace |
| custom duration/easing literals | --poyraz-motion-duration-* / --poyraz-motion-ease-* | replace |
| custom border radius literals | --poyraz-radius-* | replace |
Source route: remove V2 runtime theme objects
The registry theme owns variables. A provider-independent application only needs to set the selector consumed by the preset.
export function setColorTheme(theme: "light" | "dark") {
document.documentElement.dataset.poyrazTheme = theme;
localStorage.setItem("color-theme", theme);
}Next.js with next-themes
"use client";
import { ThemeProvider } from "next-themes";
export function Providers({ children }: { children: React.ReactNode }) {
return (
<ThemeProvider attribute="data-poyraz-theme" defaultTheme="system" enableSystem>
{children}
</ThemeProvider>
);
}Add suppressHydrationWarning to the root html element and mount theme-dependent controls on the client.
Audit and safe codemod
pnpm migration:audit src app components
pnpm migration:tokens src app components
pnpm migration:codemod -- src app components
pnpm migration:codemod --write -- src app componentsThe codemod changes named imports only when the local registry target already exists. It does not rewrite props, compositions, namespace imports or consumer component files.
Overwrite and rollback policy
- Commit before each registry install and never enable global overwrite.
- Keep consumer customization in a separate commit from upstream source updates.
- Rollback the component-specific commit and restore its pinned V2 import.
- Remove registry dependencies only after checking migrated dependents.
- Re-run typecheck, production build, keyboard and visual checks.