Skip to content

refactor: migrate design system from PandaCSS to Tailwind v4#179

Open
whdgur5717 wants to merge 22 commits into
devfrom
refactor/tailwind-v4-migration
Open

refactor: migrate design system from PandaCSS to Tailwind v4#179
whdgur5717 wants to merge 22 commits into
devfrom
refactor/tailwind-v4-migration

Conversation

@whdgur5717

Copy link
Copy Markdown
Collaborator

Summary

PandaCSS → Tailwind v4 마이그레이션 (WIP - 완전한 마이그레이션 아님)

변경 사항

  • theme-plugin: PandaCSS preset → Tailwind v4 CSS plugin으로 재작성. 시맨틱 컬러 시스템 및 다중 테마(default/forest/ocean) 지원
  • animation-plugin: panda-animationanimation-plugin으로 리네이밍, Tailwind v4 plugin으로 재작성
  • ui: 모든 컴포넌트 recipe를 PandaCSS cva/svatailwind-variants tv로 마이그레이션. createStyleContext 타입 시스템 재설계
  • cli: init/add 명령어에서 PandaCSS 의존성 제거, Tailwind v4 기반으로 단순화
  • docs: PandaCSS 설정 제거, Tailwind v4 + theme-plugin 기반으로 전환. 모든 docs 컴포넌트 recipe 마이그레이션

아직 안 된 것

  • Storybook 완전 동작 확인
  • docs 사이트 전체 페이지 동작 확인
  • 일부 컴포넌트 스타일 미세 조정 필요

@whdgur5717 whdgur5717 force-pushed the refactor/tailwind-v4-migration branch from 4d6d0a2 to 03949d8 Compare February 19, 2026 12:12

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4d6d0a224e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


type SlotOf<R extends SlottedRecipe> = keyof ReturnType<R> & string

const StyleContext = createContext<Record<string, SlotFn>>({})

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Create a dedicated style context per recipe

StyleContext is defined at module scope, so every createStyleContext(...) call shares the same React context object. When two slotted components from different recipes are nested (common for primitives with overlapping slot names like trigger/content), one provider can overwrite the other component's slot functions and produce incorrect class names. Move the context creation back inside createStyleContext so each recipe instance has isolated context state.

Useful? React with 👍 / 👎.

@@ -1 +1 @@
{"name":"Button","dependencies":["@radix-ui/react-slot"],"files":[{"name":"index.tsx","content":"import { styled, type HTMLStyledProps } from \"@styled-system/jsx\"\nimport { button } from \"@styled-system/recipes\"\nimport * as React from \"react\"\nimport { Slot } from \"@radix-ui/react-slot\"\n\nexport type BaseButtonProps = React.ComponentPropsWithoutRef<\"button\"> & {\n asChild?: boolean\n}\n\nexport const BaseButton = React.forwardRef<HTMLButtonElement, BaseButtonProps>(\n ({ asChild, ...props }, ref) => {\n const Comp = asChild ? Slot : \"button\"\n\n return <Comp role=\"button\" ref={ref} {...props}></Comp>\n },\n)\n\nBaseButton.displayName = \"\"\n\nexport const Button = styled(BaseButton, button)\nexport type ButtonProps = HTMLStyledProps<typeof Button>\n"},{"name":"recipe.ts","content":"import { defineSafe } from \"@utils/defineSafe\"\n\nexport const buttonRecipe = defineSafe.recipe({\n className: \"button\",\n description: \"Styles for the Button component\",\n base: {\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n rounded: \"md\",\n textStyle: \"sm\",\n fontWeight: \"medium\",\n transition: \"colors\",\n cursor: \"pointer\",\n gap: \"2\",\n _focusVisible: {\n outlineColor: \"background\",\n outlineWidth: \"2px\",\n ringColor: \"ring\",\n ringOffset: \"2\",\n },\n\n _disabled: {\n cursor: \"not-allowed\",\n opacity: \"50%\",\n },\n },\n variants: {\n variant: {\n default: {\n bg: \"primary\",\n color: \"primary.foreground\",\n\n _hover: {\n bg: \"primary/90\",\n },\n },\n destructive: {\n bg: \"destructive\",\n color: \"destructive.foreground\",\n\n _hover: {\n bg: \"destructive/90\",\n },\n },\n outline: {\n border: \"input\",\n bg: \"background\",\n\n _hover: {\n bg: \"accent\",\n color: \"accent.foreground\",\n },\n },\n secondary: {\n bg: \"secondary\",\n color: \"secondary.foreground\",\n\n _hover: {\n bga: \"secondary/90\",\n },\n },\n ghost: {\n _hover: {\n bg: \"accent\",\n color: \"accent.foreground\",\n },\n },\n link: {\n color: \"primary\",\n textUnderlineOffset: \"4px\",\n\n _hover: {\n textDecoration: \"underline\",\n },\n },\n },\n size: {\n default: {\n h: \"10\",\n px: \"4\",\n py: \"2\",\n },\n sm: {\n h: \"9\",\n rounded: \"md\",\n px: \"3\",\n },\n lg: {\n h: \"11\",\n rounded: \"md\",\n px: \"8\",\n },\n icon: {\n h: \"10\",\n w: \"10\",\n },\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n})\n"}]} No newline at end of file
{"name":"button","dependencies":["radix-ui","tailwind-variants"],"files":[{"name":"index.tsx","content":"import { cn } from \"@utils/cn\"\nimport { Slot } from \"radix-ui\"\nimport type { ComponentPropsWithoutRef } from \"react\"\nimport { forwardRef } from \"react\"\n\nimport { type ButtonVariantProps, recipe } from \"./recipe\"\n\nexport type ButtonProps = ComponentPropsWithoutRef<\"button\"> & {\n asChild?: boolean\n} & ButtonVariantProps\n\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(\n ({ asChild, className, size, variant, ...props }, ref) => {\n const Comp = asChild ? Slot.Root : \"button\"\n return (\n <Comp\n ref={ref}\n className={cn(recipe({ size, variant }), className)}\n {...props}\n />\n )\n },\n)\n\nButton.displayName = \"Button\"\n","type":"ui"},{"name":"recipe.ts","content":"import { tv, type VariantProps } from \"tailwind-variants\"\n\nexport type ButtonVariantProps = VariantProps<typeof recipe>\n\nexport const recipe = tv({\n base: [\n \"inline-flex shrink-0 items-center justify-center gap-1\",\n \"min-h-9 cursor-pointer rounded-md whitespace-nowrap\",\n \"text-sm/snug font-semibold tracking-wide\",\n \"[&_svg]:shrink-0\",\n \"disabled:cursor-not-allowed disabled:opacity-50\",\n ],\n variants: {\n size: {\n sm: `\n h-9 px-3 py-1.5 text-xs font-semibold\n [&_svg]:size-3.5\n `,\n md: `\n h-10 px-4 py-2\n [&_svg]:size-4\n `,\n lg: `\n h-11 px-5 py-2\n [&_svg]:size-5\n `,\n },\n variant: {\n primary: `\n bg-primary text-primary-content\n hover:not-disabled:brightness-90\n `,\n secondary: `\n bg-secondary text-secondary-content\n hover:not-disabled:brightness-90\n `,\n destructive: `\n bg-error text-error-content\n hover:not-disabled:brightness-90\n `,\n outline: `\n border border-base-300 bg-base-100 text-base-content\n hover:not-disabled:bg-base-200\n `,\n link: `\n text-primary underline-offset-2\n hover:not-disabled:underline\n `,\n },\n },\n defaultVariants: {\n size: \"md\",\n variant: \"primary\",\n },\n})\n","type":"ui"}]} No newline at end of file

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Add cn utility runtime deps to component registry

This registry payload now emits components that import @utils/cn, but the dependency list does not include clsx or tailwind-merge. Since init generates cn.ts with those imports, a fresh project that runs init + add button will fail at build/runtime module resolution unless users manually install extra packages. Include clsx and tailwind-merge in registry dependencies (or install them during init) to keep generated code runnable.

Useful? React with 👍 / 👎.

@coderabbitai

coderabbitai Bot commented Feb 19, 2026

Copy link
Copy Markdown

Important

Review skipped

Too many files!

This PR contains 162 files, which is 12 over the limit of 150.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/tailwind-v4-migration

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@whdgur5717 whdgur5717 force-pushed the refactor/tailwind-v4-migration branch from 3bad0b9 to d012bcc Compare February 19, 2026 12:28
@whdgur5717 whdgur5717 force-pushed the refactor/tailwind-v4-migration branch from d012bcc to 8b7263e Compare February 19, 2026 12:30
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