Co-authored-by: SuYao <sy20010504@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: fullex <106392080+0xfullex@users.noreply.github.com> Signed-off-by: kangfenmao <kangfenmao@qq.com> Signed-off-by: suyao <sy20010504@gmail.com>
@cherrystudio/ui
Cherry Studio UI component library for React applications.
✨ Features
- 🎨 Design System: Full Cherry Studio design tokens with 17 color families, 11 shades, and semantic theme mappings
- 🌓 Dark Mode: Built-in light and dark theme support
- 🚀 Tailwind v4: Built on top of the latest Tailwind CSS v4
- 📦 Flexible Imports: Two style integration modes for different adoption paths
- 🔷 TypeScript: Complete type definitions and editor support
- 🎯 Low Collision: CSS variable isolation without taking over app runtime state by default
🚀 Quick Start
Install
npm install @cherrystudio/ui
# peer dependencies
npm install motion react react-dom tailwindcss
The recommended integration style in this repository is to use the package export entry points:
@cherrystudio/ui@cherrystudio/ui/components@cherrystudio/ui/icons@cherrystudio/ui/utils@cherrystudio/ui/styles/*
Two Integration Modes
Mode 1: Full Theme Contract ✨
Use the full Cherry Studio design system so Tailwind theme tokens resolve to Cherry Studio values.
/* app.css */
@import '@cherrystudio/ui/styles/theme.css';
Characteristics:
- ✅ Use standard Tailwind utility names directly (
bg-primary,bg-red-500,p-md,rounded-lg) - ✅ Colors resolve to Cherry Studio design values
- ✅ Includes the extended spacing scale (
p-5xsthroughp-8xl, 16 semantic sizes) - ✅ Includes the extended radius scale (
rounded-4xsthroughrounded-3xl, plusrounded-round) - ⚠️ Overrides the default Tailwind theme contract for the imported app bundle
Example:
<Button className="bg-primary text-red-500 p-md rounded-lg">
{/* bg-primary -> Cherry Studio brand color */}
{/* text-red-500 -> Cherry Studio red-500 */}
{/* p-md -> semantic spacing token */}
{/* rounded-lg -> semantic radius token */}
</Button>
{/* Extended utility classes */}
<div className="p-5xs">Tiny spacing (0.5rem)</div>
<div className="p-xs">Extra small spacing (1rem)</div>
<div className="p-sm">Small spacing (1.5rem)</div>
<div className="p-md">Medium spacing (2.5rem)</div>
<div className="p-lg">Large spacing (3.5rem)</div>
<div className="p-xl">Extra large spacing (5rem)</div>
<div className="p-8xl">Maximum spacing (15rem)</div>
<div className="rounded-4xs">Tiny radius (0.03125rem)</div>
<div className="rounded-xs">Small radius (0.125rem)</div>
<div className="rounded-md">Medium radius (0.5rem)</div>
<div className="rounded-xl">Large radius (0.875rem)</div>
<div className="rounded-round">Full radius (999px)</div>
Mode 2: Selective Token Consumption 🎯
Import only the design tokens and decide which theme mappings your app wants to expose.
/* app.css */
@import 'tailwindcss';
@import '@cherrystudio/ui/styles/tokens.css';
/* Re-export only the parts you need */
@theme {
--color-primary: var(--cs-primary); /* Use the Cherry Studio primary color */
--color-red-500: oklch(...); /* Keep your own red scale */
--spacing-md: var(--cs-size-md); /* Reuse Cherry Studio spacing */
--radius-lg: 1rem; /* Keep your own radius */
}
Characteristics:
- ✅ Does not override the full Tailwind theme
- ✅ Gives access to all Cherry Studio design tokens through CSS variables (
var(--cs-primary),var(--cs-red-500)) - ✅ Lets you choose what to adopt and what to keep
- ✅ Works well when you already have a design system and only want selected Cherry Studio tokens
Example:
{/* Use Cherry Studio tokens directly via CSS variables */}
<button style={{ backgroundColor: 'var(--cs-primary)' }}>
Use the Cherry Studio brand color
</button>
{/* Keep your original Tailwind theme untouched */}
<div className="bg-red-500">
Use the default Tailwind red
</div>
{/* Available CSS variables */}
<div
style={{
color: 'var(--cs-primary)', // Brand color
backgroundColor: 'var(--cs-red-500)', // Red-500
padding: 'var(--cs-size-md)', // Spacing
borderRadius: 'var(--cs-radius-lg)', // Radius
}}
/>
CSS Variable Rules
To avoid mixing tokens, theme mappings, and runtime overrides, use the following rules:
--cs-*is the design token namespace, sourced fromtokens/*--color-*,--radius-*, and--font-*are public theme contracts and should be the default choice for components and external consumers--cs-theme-*is a runtime override input and should only be used for controlled runtime overrides--primaryis a compatibility alias kept for shadcn / Tailwind ecosystem compatibility and should not be preferred in new code
Default consumption rules:
- Regular application packages should depend on
@cherrystudio/ui/styles/theme.cssby default - Regular application packages should prefer public contracts such as
--color-*and should not bind directly to primitive tokens like--cs-brand-500 - Only design-system-adjacent packages that explicitly need token-level access should depend on
@cherrystudio/ui/styles/tokens.css - Runtime theme logic should only write to controlled entry variables such as
--cs-theme-*, not directly to derived--color-*variables
Usage
Basic Components
import { Button, Input } from '@cherrystudio/ui'
function App() {
return (
<div>
<Button variant="primary" size="md">Click me</Button>
<Input
type="text"
placeholder="Type here"
onChange={(value) => console.log(value)}
/>
</div>
)
}
Modular Imports
// Components only
import { Button } from '@cherrystudio/ui/components'
// Utilities only
import { cn, formatFileSize } from '@cherrystudio/ui/utils'
Development
# Install dependencies
pnpm install
# Development mode
pnpm dev
# Build
pnpm build
# Type check
pnpm type-check
# Run tests
pnpm test
Package Surface
The packages/ui workspace contains both runtime code and development-only assets.
- Runtime surface:
src/dist/build output- package export entry points declared in
package.json
- Development assets:
stories/and.storybook/scripts/used for icon and theme generationicons/source assets used by the generation pipelinedocs/for migration and reference material
Only the runtime surface should be treated as consumable package API.
Directory Structure
docs/ # Migration plans and reference docs
src/
├── components/
│ ├── primitives/ # Primitive components
│ ├── composites/ # Composite components
│ ├── icons/ # Icon runtime exports and catalogs
│ └── index.ts
├── hooks/ # React Hooks
├── lib/ # Internal utilities
├── styles/ # Tokens and theme entry files
├── utils/ # Utility functions
└── index.ts # Main runtime entry point
scripts/ # Theme and icon generation tooling
stories/ # Storybook stories and sandbox usage
icons/ # Raw icon assets for code generation
Naming Conventions
All file and directory names under packages/ui/ follow kebab-case (per shadcn CLI convention and project-wide rule §4.5 in ../../docs/references/naming-conventions.md). This covers primitives/, composites/, icons/, hooks/, and stories/ alike. Exported identifiers inside files remain PascalCase for components and camelCase for utilities and hooks.
Examples:
button.tsxexportsButtondata-table.tsxexportsDataTableerror-boundary/index.tsxexportsErrorBoundaryuse-dnd-reorder.tsexportsuseDndReorder
Components
Button
A button component with multiple variants and sizes.
Props:
variant: 'primary' | 'secondary' | 'outline' | 'ghost' | 'danger'size: 'sm' | 'md' | 'lg'loading: booleanfullWidth: booleanleftIcon/rightIcon: React.ReactNode
Input
An input component with error handling and password visibility support.
Props:
type: 'text' | 'password' | 'email' | 'number'error: booleanerrorMessage: stringonChange: (value: string) => void
Hooks
useDebounce
Debounces state updates or callback execution.
useLocalStorage
React hook wrapper for local storage.
useClickOutside
Detects clicks outside an element.
useCopyToClipboard
Copies text to the clipboard.
Utilities
cn(...inputs)
Class name merge helper built on top of clsx.
formatFileSize(bytes)
Formats byte sizes into readable strings.
debounce(func, delay)
Debounce helper.
throttle(func, delay)
Throttle helper.
License
MIT