组件包装架构Skill component-wrapper-architecture

这个技能用于在React项目中包装现有的shadcn/ui组件,以添加8位复古风格,同时确保向后兼容性和代码重用。关键词包括:组件包装、8位风格、shadcn/ui、React、TypeScript、前端开发、复古UI。

前端开发 0 次安装 0 次浏览 更新于 3/9/2026

name: component-wrapper-architecture description: 包装shadcn/ui组件的最佳实践。适用于创建现有shadcn/ui组件的8位风格变体。

组件包装架构

8位组件包装shadcn/ui组件而不是替换它们。这种模式在添加复古风格的同时保持兼容性。

基本包装模式

结构:

  1. 使用别名导入基础组件
  2. 使用class-variance-authority定义变体
  3. 导出单独的props接口
  4. 使用ref prop(对于React 19,不使用forwardRef)
import { type VariantProps, cva } from "class-variance-authority";
import { cn } from "@/lib/utils";
import { Button as ShadcnButton } from "@/components/ui/button";
import "@/components/ui/8bit/styles/retro.css";

export const buttonVariants = cva("", {
  variants: {
    font: {
      normal: "",
      retro: "retro",
    },
    variant: {
      default: "bg-foreground",
      // ...
    },
  },
  defaultVariants: {
    variant: "default",
    size: "default",
  },
});

export interface BitButtonProps
  extends React.ButtonHTMLAttributes<HTMLButtonElement>,
    VariantProps<typeof buttonVariants> {
  asChild?: boolean;
  ref?: React.Ref<HTMLButtonElement>;
}

function Button({ children, asChild, ...props }: BitButtonProps) {
  const { variant, size, className, font } = props;

  return (
    <ShadcnButton
      {...props}
      className={cn(
        "rounded-none active:translate-y-1 transition-transform",
        className
      )}
      size={size}
      variant={variant}
      asChild={asChild}
    >
      {children}
    </ShadcnButton>
  );
}

重新导出基础组件

对于具有多个子组件的组件,重新导出未更改的部分:

import {
  Dialog as ShadcnDialog,
  DialogHeader as ShadcnDialogHeader,
  DialogFooter as ShadcnDialogFooter,
  DialogDescription as ShadcnDialogDescription,
} from "@/components/ui/dialog";

const Dialog = ShadcnDialog;
const DialogHeader = ShadcnDialogHeader;
const DialogFooter = ShadcnDialogFooter;
const DialogDescription = ShadcnDialogDescription;

export {
  Dialog,
  DialogHeader,
  DialogFooter,
  DialogDescription,
  // ...自定义实现
};

卡片包装模式

使用外部包装器添加像素化边框,同时保留基础组件:

function Card({ className, font, ...props }: BitCardProps) {
  return (
    <div
      className={cn(
        "relative border-y-6 border-foreground dark:border-ring !p-0",
        className
      )}
    >
      <ShadcnCard
        {...props}
        className={cn(
          "rounded-none border-0 !w-full",
          font !== "normal" && "retro",
          className
        )}
      />

      {/* 像素化侧边框 */}
      <div
        className="absolute inset-0 border-x-6 -mx-1.5 border-foreground dark:border-ring pointer-events-none"
        aria-hidden="true"
      />
    </div>
  );
}

关键原则

  1. 别名导入 - 使用 as ShadcnComponent 模式导入基础组件
  2. 空的cva基础 - 变体通常从空开始,依赖CSS进行样式化
  3. 单独的props接口 - 为TypeScript导出 BitComponentProps
  4. React 19 ref - 使用 ref?: React.Ref<T> 而不是forwardRef
  5. rounded-none - 从基础组件中移除所有边框半径
  6. 传递props - 转发所有props,包括 sizevariantclassName
  7. 条件复古 - 使用 font !== "normal" && "retro" 模式

组件示例

  • components/ui/8bit/button.tsx - 带有像素边框的基本包装器
  • components/ui/8bit/card.tsx - 带有外部包装器的卡片
  • components/ui/8bit/dialog.tsx - 多子组件包装器