设计系统组件:CVA 与 Surface 原语 - Openclaw Skills

作者:互联网

2026-03-30

AI教程

什么是 设计系统组件?

设计系统组件技能为开发严格遵循设计令牌的可扩展 UI 库提供了专业架构。通过利用 Openclaw Skills,开发人员可以实现 Surface 原语模式,该模式为面板、磁贴和碎片等所有分层 UI 元素提供单一、统一的组件。

这种方法利用了 class-variance-authority (CVA) 的强大功能,以类型安全的方式管理复杂的组件状态和样式。它确保整个应用程序的样式保持一致,同时通过基于变体的 API 提供高度灵活性,使其成为使用 React 和 Tailwind CSS 构建现代设计系统的团队的重要资源。

下载入口:https://github.com/openclaw/skills/tree/main/skills/wpank/design-system-components

安装与下载

1. ClawHub CLI

从源直接安装技能的最快方式。

npx clawhub@latest install design-system-components

2. 手动安装

将技能文件夹复制到以下位置之一

全局模式 ~/.openclaw/skills/ 工作区 /skills/

优先级:工作区 > 本地 > 内置

3. 提示词安装

将此提示词复制到 OpenClaw 即可自动安装。

请帮我使用 Clawhub 安装 design-system-components。如果尚未安装 Clawhub,请先安装(npm i -g clawhub)。

设计系统组件 应用场景

  • 创建遵循统一设计令牌架构的集中式组件库。
  • 构建需要一致图层和背景模糊效果的复杂 UI 布局。
  • 为 React 应用程序开发类型安全的组件 API 以提升开发体验。
  • 在各种 Openclaw Skills 工作流中标准化按钮、徽章和指标等交互元素。
  • 自动生成高质量的 UI 组件,避免硬编码样式和反模式。
设计系统组件 工作原理
  1. 定义一个核心 Surface 原语,根据特定图层处理背景、边框和阴影逻辑。
  2. 利用 class-variance-authority (CVA) 为每个组件创建样式变体的结构化映射。
  3. 直接从 CVA 定义中提取 TypeScript 接口,以确保严格的 prop 验证。
  4. 通过将按钮和卡片等高级组件包装在 Surface 原语中,或使用 cn() 工具进行类合并,来组合这些组件。
  5. 实现默认变体,确保即使在未传递 prop 的情况下,组件仍能保持功能和视觉上的正确。
  6. 通过 Openclaw Skills 将这些模式集成到您的开发环境中,以保持架构一致性。

设计系统组件 配置指南

要实现这些模式,请首先在项目中安装所需的依赖项:

npm install class-variance-authority clsx tailwind-merge

确保您拥有一个能有效合并 Tailwind 类的工具函数:

// lib/utils.ts
import { type ClassValue, clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs));
}

设计系统组件 数据架构与分类体系

该技能通过 CVA 对象内的结构化变体分类法来组织设计系统数据:

组件类型 变体键 元数据详情
Surface layer, interactive, glow 定义深度、交互性和阴影效果。
Button variant, size 管理审美意图(破坏性、赛博风)和规模。
Metric size, trend 处理等宽数字显示和正/负趋势。
Badge variant 控制状态指示器(成功、警告等)。
Card 布局 Props 通过组合管理标题、描述和动作插槽。
name: design-system-components
model: standard
description: Patterns for building design system components using Surface primitives, CVA variants, and consistent styling. Use when building reusable UI components that follow design token architecture. Triggers on Surface component, CVA, class-variance-authority, component variants, design tokens.

Design System Components

Build reusable components that leverage design tokens with Surface primitives and CVA (class-variance-authority).


When to Use

  • Building component libraries with design tokens
  • Need variant-based styling (size, color, state)
  • Creating layered UI with consistent surfaces
  • Want type-safe component APIs

Pattern 1: Surface Primitive

Single component for all layered surfaces:

import { cva, type VariantProps } from 'class-variance-authority';
import { cn } from '@/lib/utils';

const surfaceVariants = cva(
  'rounded-lg backdrop-blur-sm transition-colors',
  {
    variants: {
      layer: {
        panel: 'bg-tone-cadet/40 border border-tone-jordy/10 shadow-card',
        tile: 'bg-tone-midnight/60 border border-tone-jordy/5',
        chip: 'bg-tone-cyan/10 border border-tone-cyan/20 rounded-full',
        deep: 'bg-tone-void/80',
        metric: 'bg-tone-cadet/20 border border-tone-jordy/8',
        glass: 'bg-glass-bg backdrop-blur-lg border border-glass-border',
      },
      interactive: {
        true: 'cursor-pointer hover:bg-tone-cadet/50 active:scale-[0.98]',
        false: '',
      },
      glow: {
        true: 'shadow-glow',
        false: '',
      },
    },
    defaultVariants: {
      layer: 'tile',
      interactive: false,
      glow: false,
    },
  }
);

interface SurfaceProps
  extends React.HTMLAttributes,
    VariantProps {}

export function Surface({
  layer,
  interactive,
  glow,
  className,
  ...props
}: SurfaceProps) {
  return (
    
); }

Usage


  

Dashboard

Active $1,234.56

Pattern 2: CVA Button Variants

const buttonVariants = cva(
  'inline-flex items-center justify-center rounded-md font-medium transition-all focus-visible:outline-none focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50',
  {
    variants: {
      variant: {
        default: 'bg-primary text-primary-foreground hover:bg-primary/90',
        destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
        outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
        ghost: 'hover:bg-accent hover:text-accent-foreground',
        link: 'text-primary underline-offset-4 hover:underline',
        cyber: 'bg-gradient-to-r from-tone-cadet to-tone-azure text-white border border-tone-cyan/30 shadow-glow hover:shadow-glow-lg',
      },
      size: {
        default: 'h-10 px-4 py-2',
        sm: 'h-9 rounded-md px-3',
        lg: 'h-11 rounded-md px-8',
        icon: 'h-10 w-10',
      },
    },
    defaultVariants: {
      variant: 'default',
      size: 'default',
    },
  }
);

Pattern 3: Metric Display Component

const metricVariants = cva(
  'font-mono tabular-nums',
  {
    variants: {
      size: {
        lg: 'text-3xl font-bold tracking-tight',
        md: 'text-xl font-semibold',
        sm: 'text-base font-medium',
      },
      trend: {
        positive: 'text-success',
        negative: 'text-destructive',
        neutral: 'text-foreground',
      },
    },
    defaultVariants: {
      size: 'md',
      trend: 'neutral',
    },
  }
);

interface MetricProps extends VariantProps {
  value: string | number;
  label?: string;
  prefix?: string;
  suffix?: string;
}

export function Metric({
  value,
  label,
  prefix = '',
  suffix = '',
  size,
  trend,
}: MetricProps) {
  return (
    
{label && ( {label} )} {prefix}{value}{suffix}
); }

Pattern 4: Card with Header

interface CardProps {
  title?: string;
  description?: string;
  action?: React.ReactNode;
  children: React.ReactNode;
}

export function Card({ title, description, action, children }: CardProps) {
  return (
    
      {(title || action) && (
        
{title && (

{title}

)} {description && (

{description}

)}
{action}
)}
{children}
); }

Pattern 5: Badge/Chip Variants

const badgeVariants = cva(
  'inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium transition-colors',
  {
    variants: {
      variant: {
        default: 'bg-primary/10 text-primary border border-primary/20',
        success: 'bg-success/10 text-success border border-success/20',
        warning: 'bg-warning/10 text-warning border border-warning/20',
        destructive: 'bg-destructive/10 text-destructive border border-destructive/20',
        outline: 'border border-input text-foreground',
      },
    },
    defaultVariants: {
      variant: 'default',
    },
  }
);

Pattern 6: Composing Variants

Combine CVA with conditional classes:

function StatusIndicator({ 
  status, 
  size = 'md' 
}: { 
  status: 'online' | 'offline' | 'away';
  size?: 'sm' | 'md' | 'lg';
}) {
  const sizeClasses = {
    sm: 'size-2',
    md: 'size-3',
    lg: 'size-4',
  };

  const statusClasses = {
    online: 'bg-success animate-pulse',
    offline: 'bg-muted-foreground',
    away: 'bg-warning',
  };

  return (
    
  );
}

  • Meta-skill: ai/skills/meta/design-system-creation/ — Complete design system workflow
  • distinctive-design-systems — Token architecture and aesthetic foundations
  • loading-state-patterns — Skeleton components for loading states

NEVER Do

  • Build custom card containers — Use Surface primitive
  • Hardcode colors in components — Use design tokens
  • Skip variant types — CVA provides type safety
  • Mix styling approaches — Pick CVA or cn(), not random inline styles
  • Forget default variants — Components should work without props

Quick Reference

// 1. Define variants with CVA
const variants = cva('base-classes', {
  variants: {
    size: { sm: '...', md: '...', lg: '...' },
    color: { primary: '...', secondary: '...' },
  },
  defaultVariants: { size: 'md', color: 'primary' },
});

// 2. Type props from variants
interface Props extends VariantProps {}

// 3. Apply in component