设计原则
指导 HeroUI v3 设计和开发的核心原则
HeroUI v3 遵循 10 项核心原则,注重清晰度、无障碍、可定制性以及开发者体验。
核心原则
1. 语义意图优于视觉风格
使用语义命名(primary、secondary、tertiary),而非视觉描述(solid、flat、bordered)。灵感来自 Uber 的 Base 设计系统,变体遵循清晰的层次结构:
// ✅ Semantic variants communicate hierarchy<Button variant="primary">Save</Button><Button variant="secondary">Edit</Button><Button variant="tertiary">Cancel</Button>| 变体 | 用途 | 使用方式 |
|---|---|---|
| Primary | 推进流程的主要操作 | 每种场景 1 个 |
| Secondary | 备选操作 | 可使用多个 |
| Tertiary | 次要操作(取消、跳过) | 谨慎使用 |
| Danger | 破坏性操作 | 需要时使用 |
2. 无障碍是基础
基于 React Aria Components 构建,符合 WCAG 2.1 AA 标准。内置自动 ARIA 属性、键盘导航与屏幕阅读器支持。
import { Tabs, TabList, Tab, TabPanel } from '@lenso/ui';
<Tabs defaultSelectedKey="profile"> <TabList aria-label="Settings"> <Tab id="profile">Profile</Tab> <Tab id="security">Security</Tab> </TabList> <TabPanel id="profile">Content</TabPanel> <TabPanel id="security">Content</TabPanel></Tabs>3. 组合优于配置
复合组件允许你按需重新组合、自定义或省略其中的各个部分。可以使用点号语法、命名导出,或两者混合使用。
// Compose parts to build exactly what you needimport { Accordion, AccordionItem, AccordionHeading, AccordionTrigger, AccordionIndicator, AccordionPanel, AccordionBody} from '@lenso/ui';
<Accordion> <AccordionItem id="1"> <AccordionHeading> <AccordionTrigger> Question Text <AccordionIndicator /> </AccordionTrigger> </AccordionHeading> <AccordionPanel> <AccordionBody>Answer content</AccordionBody> </AccordionPanel> </AccordionItem></Accordion>4. 渐进式呈现
从简单开始,仅在需要时才增加复杂度。组件只需最少的 props 即可工作,并能随需求增长而扩展。
// Level 1: Minimal<Button>Click me</Button>
// Level 2: Enhanced<Button variant="primary" size="lg"> <Icon icon="gravity-ui:check" className="mr-2" /> Submit</Button>
// Level 3: Advanced<Button variant="primary" isDisabled={isLoading}> {isLoading ? <><Spinner size="sm" className="mr-2" /> Loading...</> : 'Submit'}</Button>5. 可预测的行为
所有组件遵循一致的模式:尺寸(sm、md、lg)、变体、className 支持以及 data 属性。相同的 API,相同的行为。
// All components follow the same patterns<Button size="lg" variant="primary" className="custom" data-pressed="true" /><Chip size="lg" variant="success" className="custom" /><Avatar size="lg" className="custom" />
// Compound components support both named exports and dot notationimport { Alert, AlertIcon, CardHeader, AccordionTrigger } from '@lenso/ui';
// Named exports<Alert> <AlertIcon /></Alert>
// Dot notation<Alert> <Alert.Icon /></Alert>6. 类型安全优先
完整的 TypeScript 支持,包括 IntelliSense、自动补全与编译时错误检测。可为自定义组件扩展类型。
import type { ButtonProps } from '@lenso/ui';
// Type-safe props and event handlers<Button variant="primary" // Autocomplete: primary | secondary | tertiary | danger | ghost size="md" // Type checked: sm | md | lg onPress={(e) => { // e is properly typed as PressEvent console.log(e.target); }}/>
// Extend types for custom componentsinterface CustomButtonProps extends Omit<ButtonProps, 'variant'> { intent: 'save' | 'cancel' | 'delete';}7. 样式与逻辑分离
样式(@lenso/tokens)与逻辑(@lenso/ui)相互分离,可与任何框架或纯 HTML 一同使用。参见 Tailwind Play 示例。
<!-- Use with plain HTML --><button class="button button--primary">Click me</button>或与 React 一同使用:
// Apply styles to any componentimport { buttonVariants } from '@lenso/tokens';
<Link className={buttonVariants({ variant: "primary" })} href="/home"> Home</Link>8. 卓越的开发者体验
清晰的 API、富含信息的错误提示、IntelliSense、对 AI 友好的 Markdown 文档,以及用于可视化测试的 Storybook。
9. 完全可定制
开箱即用的精美默认样式。使用 CSS 变量或 BEM 类即可彻底改变整体外观。每一个插槽都可定制。
/* Theme-wide changes with variables */:root { --accent: oklch(0.7 0.25 260); --radius: 0.375rem; --spacing: 0.5rem;}
/* Component-specific customization */@layer components { .button { @apply uppercase tracking-wider; } .button--primary { @apply bg-gradient-to-r from-purple-500 to-pink-500; }}10. 开放且可扩展
可以包装、扩展或自定义组件以满足你的需求。可以使用变体函数、直接应用 BEM 类,或创建自定义的包装组件。
使用变体函数应用样式:
import { Link } from '@lenso/ui';import { linkVariants } from '@lenso/tokens';import NextLink from 'next/link';
// Use variant functions to style framework-specific componentsconst slots = linkVariants({ underline: "hover" });
<NextLink className={slots.base()} href="/about"> About Page <Link.Icon className={slots.icon()} /></NextLink>直接应用 BEM 类:
import Link from 'next/link';
// Apply HeroUI's BEM classes directly to any element<Link className="button button--primary" href="/dashboard"> Dashboard</Link>创建自定义包装组件:
// Custom wrapper componentconst CTAButton = ({ intent = 'primary-cta', children, ref, ...props}: CTAButtonProps) => { const variantMap = { 'primary-cta': 'primary', 'secondary-cta': 'secondary', 'minimal': 'ghost' };
return ( <Button ref={ref} variant={variantMap[intent]} {...props}> {children} </Button> );};使用 Tailwind Variants 扩展:
import { Button } from '@lenso/ui';import { buttonVariants, tv } from '@lenso/tokens';
// Extend button styles with custom variantsconst myButtonVariants = tv({ extend: buttonVariants, variants: { variant: { 'primary-cta': 'bg-gradient-to-r from-blue-500 to-purple-600 text-white shadow-lg', 'secondary-cta': 'border-2 border-blue-500 text-blue-500 hover:bg-blue-50', } }});
// Use the custom variantsfunction CustomButton({ variant, className, ...props }) { return <Button className={myButtonVariants({ variant, className })} {...props} />;}
// Usage<CustomButton variant="primary-cta">Get Started</CustomButton><CustomButton variant="secondary-cta">Learn More</CustomButton>与 HeroUI v2 的对比
| 维度 | HeroUI v2 | HeroUI v3 |
|---|---|---|
| 动画 | Framer Motion | CSS + GPU 加速 |
| 组件模式 | 带有大量 props 的单一组件 | 复合组件 |
| 变体 | 基于视觉(solid、bordered、flat) | 基于语义(primary、secondary、tertiary) |
| 样式 | 部分支持 Tailwind v4 | 完整支持 Tailwind v4 |
| 无障碍 | 优秀(基于 React Aria) | 优秀(基于 React Aria) |
| 打包体积 | 较大(整体打包) | 较小(支持 tree-shaking) |
| 自定义难度 | 中等(基于 props) | 简单(复合组件 + 原生 CSS) |