@ducksauce/ui
v2.0.0
Published
A modern React component library built with Tailwind CSS, Radix UI, and Class Variance Authority (CVA). Provides accessible, customizable components with a consistent design system.
Readme
@ducksauce/ui
A modern React component library built with Tailwind CSS, Radix UI, and Class Variance Authority (CVA). Provides accessible, customizable components with a consistent design system.
🚀 Quick Start
Installation
npm install @ducksauce/ui
# or
yarn add @ducksauce/ui
# or
pnpm add @ducksauce/uiUsage
import { Button, Card, ThemeProvider } from "@ducksauce/ui";
function App() {
return (
<ThemeProvider defaultTheme="dark">
<Card>
<Button variant="solid">Click me</Button>
</Card>
</ThemeProvider>
);
}🎨 Components
Button
A versatile button component with multiple variants and sizes.
import { Button } from '@ducksauce/ui'
// Variants
<Button variant="solid">Solid</Button>
<Button variant="outline">Outline</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="destructive">Destructive</Button>
// Sizes
<Button size="sm">Small</Button>
<Button size="md">Medium</Button>
<Button size="lg">Large</Button>
<Button size="icon">🚀</Button>
// With asChild prop
<Button asChild>
<a href="/link">Link Button</a>
</Button>Card
A flexible card component with header, content, and footer sections.
import {
Card,
CardHeader,
CardTitle,
CardDescription,
CardContent,
CardFooter,
} from "@ducksauce/ui";
<Card variant="elevated" padding="lg">
<CardHeader>
<CardTitle>Card Title</CardTitle>
<CardDescription>Card description</CardDescription>
</CardHeader>
<CardContent>
<p>Card content goes here</p>
</CardContent>
<CardFooter>
<Button>Action</Button>
</CardFooter>
</Card>;ThemeProvider
A context provider for managing light/dark themes.
import { ThemeProvider, useTheme } from "@ducksauce/ui";
function App() {
return (
<ThemeProvider defaultTheme="dark" storageKey="my-theme">
<MyApp />
</ThemeProvider>
);
}
function MyApp() {
const { theme, setTheme } = useTheme();
return (
<div>
<p>Current theme: {theme}</p>
<button onClick={() => setTheme("light")}>Light</button>
<button onClick={() => setTheme("dark")}>Dark</button>
</div>
);
}🎨 Theming
CSS Variables
The design system uses CSS variables for theming:
:root {
/* Colors */
--ds-bg: #0b0b0c;
--ds-fg: #fff;
--ds-muted: #9aa0a6;
--ds-accent: #6ee7b7;
--ds-ring: #93c5fd;
--ds-border: #374151;
--ds-input: #1f2937;
/* Spacing */
--ds-radius: 1rem;
--ds-radius-sm: 0.5rem;
--ds-radius-lg: 1.5rem;
/* Typography */
--ds-font-sans: ui-sans-serif, system-ui, sans-serif;
--ds-font-mono:
ui-monospace, SFMono-Regular, "SF Mono", Consolas, "Liberation Mono", Menlo,
monospace;
/* Shadows */
--ds-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
--ds-shadow-lg:
0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
}Custom Themes
Override CSS variables to create custom themes:
:root {
--ds-accent: #ff5a1f;
--ds-radius: 8px;
--ds-bg: #ffffff;
--ds-fg: #111827;
}
.dark {
--ds-bg: #0b0b0c;
--ds-fg: #fff;
--ds-accent: #6ee7b7;
}🛠️ Development
Prerequisites
- Node.js 18.20.2 or >=20.9.0
- pnpm 10.13.1+
Setup
# Install dependencies
pnpm install
# Start development mode
pnpm dev
# Build for production
pnpm build
# Run linting
pnpm lint
# Clean build artifacts
pnpm cleanProject Structure
packages/ui/
├── src/
│ ├── components/ # React components
│ │ ├── Button.tsx
│ │ ├── Card.tsx
│ │ └── ThemeProvider.tsx
│ ├── utils/ # Utility functions
│ │ └── cn.ts
│ └── index.ts # Main exports
├── styles.css # Global styles
├── package.json
├── tsconfig.json
└── README.mdAdding New Components
- Create component file in
src/components/ - Export from
src/index.ts - Add TypeScript types
- Update this README with documentation
Example Component
import { cva, type VariantProps } from "class-variance-authority";
import * as React from "react";
import { cn } from "../utils/cn";
const componentVariants = cva("base-styles", {
variants: {
variant: {
default: "default-styles",
secondary: "secondary-styles",
},
size: {
sm: "small-styles",
md: "medium-styles",
lg: "large-styles",
},
},
defaultVariants: {
variant: "default",
size: "md",
},
});
export interface ComponentProps
extends React.HTMLAttributes<HTMLDivElement>,
VariantProps<typeof componentVariants> {}
const Component = React.forwardRef<HTMLDivElement, ComponentProps>(
({ className, variant, size, ...props }, ref) => {
return (
<div
className={cn(componentVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
);
}
);
Component.displayName = "Component";
export { Component, componentVariants };📦 Building
Development Build
pnpm devThis starts tsup in watch mode, rebuilding on file changes.
Production Build
pnpm buildThis creates:
dist/index.js- ESM bundledist/index.d.ts- TypeScript declarations
Build Configuration
The package uses tsup for building:
{
"build": "tsup src/index.ts --dts --format esm --external react --external react-dom"
}🧪 Testing
# Run tests
pnpm test
# Run tests in watch mode
pnpm test --watch
# Run tests with coverage
pnpm test --coverage📦 Publishing
Versioning
This package uses Changesets for versioning:
- Create a changeset:
pnpm changeset - Version the package:
pnpm release - Publish:
pnpm release(includes publishing)
Manual Publishing
# Build the package
pnpm build
# Publish to npm
pnpm publishPackage Configuration
{
"name": "@ducksauce/ui",
"version": "0.0.0",
"type": "module",
"main": "dist/index.js",
"module": "dist/index.js",
"types": "dist/index.d.ts",
"sideEffects": false,
"files": ["dist", "styles.css"],
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
},
"./styles.css": "./styles.css"
}
}🔗 Dependencies
Peer Dependencies
react^18 || ^19react-dom^18 || ^19
Dependencies
class-variance-authority- Component variants@radix-ui/react-slot- Polymorphic componentsclsx- Conditional classestailwind-merge- Tailwind class merging
Dev Dependencies
@types/react- React TypeScript types@types/react-dom- React DOM TypeScript types@types/node- Node.js TypeScript typeseslint- Code lintingtsup- TypeScript bundlertypescript- TypeScript compiler
📚 API Reference
Button
Props
variant?: "solid" | "outline" | "ghost" | "destructive"size?: "sm" | "md" | "lg" | "icon"asChild?: boolean- All standard button HTML attributes
Card
Props
variant?: "default" | "elevated" | "outline"padding?: "none" | "sm" | "md" | "lg"- All standard div HTML attributes
Sub-components
CardHeader- Card header sectionCardTitle- Card titleCardDescription- Card descriptionCardContent- Card content sectionCardFooter- Card footer section
ThemeProvider
Props
children: React.ReactNodedefaultTheme?: "light" | "dark"storageKey?: string
Context Value
theme: "light" | "dark"setTheme: (theme: "light" | "dark") => void
🤝 Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Create a changeset
- Submit a pull request
📄 License
This package is licensed under the MIT License - see the LICENSE file for details.
🆘 Support
- Documentation: This README
- Issues: Create an issue in the repository
- Discussions: Use GitHub Discussions for questions
Built with ❤️ using Radix UI, Tailwind CSS, and Class Variance Authority.
