cherry-studio/packages/ui
Phantom 4a38fd6ebc
feat(ui): new Switch (#11061)
* refactor(ui): migrate switch component from heroui to radix-ui

replace heroui switch implementation with radix-ui for better maintainability
update package.json and yarn.lock to include new dependency

* fix(eslint): enable heroui import restriction for deprecated Switch component

* refactor(ui): update Switch component props from isSelected/onValueChange to checked/onCheckedChange

Standardize Switch component props across the codebase to use checked/onCheckedChange instead of isSelected/onValueChange for better consistency with common React patterns. Also updates loading state prop from isLoading to loading and removes size prop where unnecessary.

The changes include:
- Replacing isSelected with checked
- Replacing onValueChange with onCheckedChange
- Updating isLoading to loading
- Removing redundant size props
- Adjusting styling to accommodate new loading state

* refactor(switch): improve switch component styling and structure

- Add default values for loading and disabled props
- Update styling classes and add group cursor pointer
- Restructure loading indicator and thumb positioning
- Wrap DescriptionSwitch children in flex container

* refactor(ui): improve switch component structure and usage

- Restructure DescriptionSwitch to use explicit props instead of children
- Add label, description, and position props for better customization
- Update all switch usages in SettingsTab to use new props format

* refactor(primitives): simplify switch props by omitting children

Remove redundant children prop from CustomSwitchProps since it's already omitted from the parent type

* fix(switch): add useId for label accessibility in DescriptionSwitch

Ensure proper label association with switch input by generating unique ID using React's useId hook

* refactor(settings): remove commented out SettingRowTitleSmall components

* refactor(SettingsTab): add todo comment for memoization optimization

* feat(switch): add size prop to customize switch dimensions

Add sm, md, and lg size options to the Switch component with corresponding styles. This allows for better visual consistency across different UI contexts.

* style(ui): adjust switch component styling and theme colors

update switch component layout and spacing to improve consistency
modify secondary-foreground color variable to use correct semantic token

* feat(switch): add new switch component styles and animations

- Add new switch.css file with gradient and transition styles
- Update switch.tsx component with new styling classes and animations
- Remove loader icon in favor of animated gradient effect

* fix(i18n): Auto update translations for PR #11061

* style(primitives): remove redundant border style from switch component

* refactor(switch): remove switch.css and update switch component styles

Remove deprecated switch.css file and migrate styles to inline tailwind classes. Update disabled state styling to use opacity instead of linear gradient for better consistency.

* refactor(switch): simplify switch thumb implementation

Replace complex div structure with svg for loading state
Adjust disabled opacity and loading state styling

* style(switch): adjust thumb size and positioning for better consistency

* feat(switch): add storybook documentation for switch component

Add comprehensive Storybook documentation for the Switch component, including:
- Basic usage examples
- Different states (checked, disabled, loading)
- Size variations
- DescriptionSwitch variant
- Real-world usage scenarios
- Accessibility examples
- Form integration examples

Also remove redundant box-content class from switch styles

* fix(switch): adjust thumb positioning for md and lg sizes

* style(primitives): improve switch component styling and spacing

- Add padding to the container
- Simplify label height logic
- Update typography classes for better consistency
- Adjust switch container alignment

* feat(switch): add size prop to DescriptionSwitch component

Add support for sm, md, and lg sizes to DescriptionSwitch component with responsive text sizing. Also includes comprehensive Storybook documentation with examples of all sizes and states.

* style(switch): align label text to right when isLeftSide is true

* refactor(stories): clean up DescriptionSwitch stories by removing unused imports and simplifying JSX

* refactor(ui): rename CustomizedSwitch to Switch for consistency

Simplify component naming by removing redundant 'Customized' prefix and aligning with common naming conventions

* refactor(switch): extract switch root styles into cva variants

Improve maintainability by using class-variance-authority to manage switch root styles and variants

* refactor(switch): extract thumb variants into separate cva function

Improve maintainability by moving switch thumb styling logic into a dedicated variants configuration. This makes the component more readable and easier to modify.

* feat(switch): add classNames prop for custom styling

Allow custom class names to be applied to switch root, thumb, and thumbSvg elements for more flexible styling options.

* feat(switch): add loading animation variants for switch thumb

Extract loading animation logic into separate cva variants for better maintainability and reusability

---------

Co-authored-by: GitHub Action <action@github.com>
2025-12-01 17:04:43 +08:00
..
.storybook feat(storybook): add background options for light and dark themes 2025-11-12 14:26:09 +08:00
design-reference feat(design-reference): restructure color tokens and remove outdated conversion log 2025-11-12 18:14:18 +08:00
icons chore: remove DmxapiToImg component and related assets 2025-11-21 18:27:30 +08:00
scripts Refactor icon management and update dependencies 2025-11-14 17:55:44 +08:00
src feat(ui): new Switch (#11061) 2025-12-01 17:04:43 +08:00
stories feat(ui): new Switch (#11061) 2025-12-01 17:04:43 +08:00
.gitignore feat: update UI package with Storybook integration and Tailwind CSS v4 configuration 2025-09-15 19:26:23 +08:00
components.json refactor: update CSS structure and improve theme integration 2025-10-31 15:31:51 +08:00
MIGRATION_STATUS.md chore: remove outdated DESIGN_SYSTEM.md and update migration documentation 2025-10-31 15:54:29 +08:00
package.json feat: add Tabs component and related subcomponents 2025-11-21 17:09:29 +08:00
README.md Merge branch 'main' into v2 2025-11-06 19:53:09 +08:00
tsconfig.json feat: update UI component stories to use centralized imports from @cherrystudio/ui 2025-11-21 13:34:02 +08:00
tsdown.config.ts refactor(ui): update migration status and enhance component implementations 2025-09-16 19:20:04 +08:00

@cherrystudio/ui

Cherry Studio UI 组件库 - 为 Cherry Studio 设计的 React 组件集合

特性

  • 🎨 设计系统: 完整的 CherryStudio 设计令牌17种颜色 × 11个色阶 + 语义化主题)
  • 🌓 Dark Mode: 开箱即用的深色模式支持
  • 🚀 Tailwind v4: 基于最新 Tailwind CSS v4 构建
  • 📦 灵活导入: 2种样式导入方式满足不同使用场景
  • 🔷 TypeScript: 完整的类型定义和智能提示
  • 🎯 零冲突: CSS 变量隔离,不覆盖用户主题

🚀 快速开始

安装

npm install @cherrystudio/ui
# peer dependencies
npm install framer-motion react react-dom tailwindcss

两种使用方式

方式 1完整覆盖

使用完整的 CherryStudio 设计系统,所有 Tailwind 类名映射到设计系统。

/* app.css */
@import '@cherrystudio/ui/styles/theme.css';

特点

  • 直接使用标准 Tailwind 类名(bg-primarybg-red-500p-mdrounded-lg
  • 所有颜色使用设计师定义的值
  • 扩展的 Spacing 系统(p-5xs ~ p-8xl,共 16 个语义化尺寸)
  • 扩展的 Radius 系统(rounded-4xs ~ rounded-3xl,共 11 个圆角)
  • ⚠️ 会完全覆盖 Tailwind 默认主题

示例

<Button className="bg-primary text-red-500 p-md rounded-lg">
  {/* bg-primary → 品牌色lime-500 */}
  {/* text-red-500 → 设计师定义的红色 */}
  {/* p-md → 2.5remspacing-md */}
  {/* rounded-lg → 2.5remradius-lg */}
</Button>

{/* 扩展的工具类 */}
<div className="p-5xs">最小间距 (0.5rem)</div>
<div className="p-xs">超小间距 (1rem)</div>
<div className="p-sm">小间距 (1.5rem)</div>
<div className="p-md">中等间距 (2.5rem)</div>
<div className="p-lg">大间距 (3.5rem)</div>
<div className="p-xl">超大间距 (5rem)</div>
<div className="p-8xl">最大间距 (15rem)</div>

<div className="rounded-4xs">最小圆角 (0.25rem)</div>
<div className="rounded-xs">小圆角 (1rem)</div>
<div className="rounded-md">中等圆角 (2rem)</div>
<div className="rounded-xl">大圆角 (3rem)</div>
<div className="rounded-round">完全圆角 (999px)</div>

方式 2选择性覆盖 🎯

只导入设计令牌CSS 变量),手动选择要覆盖的部分。

/* app.css */
@import 'tailwindcss';
@import '@cherrystudio/ui/styles/tokens.css';

/* 只使用部分设计系统 */
@theme {
  --color-primary: var(--cs-primary);     /* 使用 CS 的主色 */
  --color-red-500: oklch(...);            /* 使用自己的红色 */
  --spacing-md: var(--cs-size-md);        /* 使用 CS 的间距 */
  --radius-lg: 1rem;                      /* 使用自己的圆角 */
}

特点

  • 不覆盖任何 Tailwind 默认主题
  • 通过 CSS 变量访问所有设计令牌(var(--cs-primary)var(--cs-red-500)
  • 精细控制哪些使用 CS、哪些保持原样
  • 适合有自己设计系统但想借用部分 CS 设计令牌的场景

示例

{/* 通过 CSS 变量使用 CS 设计令牌 */}
<button style={{ backgroundColor: 'var(--cs-primary)' }}>
  使用 CherryStudio 品牌色
</button>

{/* 保持原有的 Tailwind 类名不受影响 */}
<div className="bg-red-500">
  使用 Tailwind 默认的红色
</div>

{/* 可用的 CSS 变量 */}
<div style={{
  color: 'var(--cs-primary)',           // 品牌色
  backgroundColor: 'var(--cs-red-500)', // 红色-500
  padding: 'var(--cs-size-md)',         // 间距
  borderRadius: 'var(--cs-radius-lg)'   // 圆角
}} />

Provider 配置

在你的 App 根组件中添加 HeroUI Provider

import { HeroUIProvider } from '@heroui/react'

function App() {
  return (
    <HeroUIProvider>
      {/* 你的应用内容 */}
    </HeroUIProvider>
  )
}

使用

基础组件

import { Button, Input } from '@cherrystudio/ui'

function App() {
  return (
    <div>
      <Button variant="primary" size="md">
        点击我
      </Button>
      <Input
        type="text"
        placeholder="请输入内容"
        onChange={(value) => console.log(value)}
      />
    </div>
  )
}

分模块导入

// 只导入组件
import { Button } from '@cherrystudio/ui/components'

// 只导入工具函数
import { cn, formatFileSize } from '@cherrystudio/ui/utils'

开发

# 安装依赖
yarn install

# 开发模式(监听文件变化)
yarn dev

# 构建
yarn build

# 类型检查
yarn type-check

# 运行测试
yarn test

目录结构

src/
├── components/          # React 组件
│   ├── Button/         # 按钮组件
│   ├── Input/          # 输入框组件
│   └── index.ts        # 组件导出
├── hooks/              # React Hooks
├── utils/              # 工具函数
├── types/              # 类型定义
└── index.ts            # 主入口文件

组件列表

Button 按钮

支持多种变体和尺寸的按钮组件。

Props:

  • variant: 'primary' | 'secondary' | 'outline' | 'ghost' | 'danger'
  • size: 'sm' | 'md' | 'lg'
  • loading: boolean
  • fullWidth: boolean
  • leftIcon / rightIcon: React.ReactNode

Input 输入框

带有错误处理和密码显示切换的输入框组件。

Props:

  • type: 'text' | 'password' | 'email' | 'number'
  • error: boolean
  • errorMessage: string
  • onChange: (value: string) => void

Hooks

useDebounce

防抖处理,延迟执行状态更新。

useLocalStorage

本地存储的 React Hook 封装。

useClickOutside

检测点击元素外部区域。

useCopyToClipboard

复制文本到剪贴板。

工具函数

cn(...inputs)

基于 clsx 的类名合并工具,支持条件类名。

formatFileSize(bytes)

格式化文件大小显示。

debounce(func, delay)

防抖函数。

throttle(func, delay)

节流函数。

许可证

MIT