@yca-software/design-system
v0.1.1
Published
Shared React component library built with shadcn/ui and Tailwind CSS. Published as a **public** npm package.
Readme
@yca-software/design-system
Shared React component library built with shadcn/ui and Tailwind CSS. Published as a public npm package.
Publishing to npm
CI (push to main): The publish workflow uses NPM_TOKEN (npm automation token or auth token) and publishes to the public npm registry.
Local publish:
- Authenticate with npm (e.g.
npm loginor setNPM_TOKEN). - Publish (from this directory):
pnpm publish --no-git-checks
Installation (consumers)
Install from public npm (no .npmrc auth required):
pnpm add @yca-software/design-systemUsage
Basic UI Components
import { Button, Input, Label, Card } from "@yca-software/design-system";
function MyComponent() {
return (
<Card>
<Label htmlFor="email">Email</Label>
<Input id="email" type="email" />
<Button>Submit</Button>
</Card>
);
}Marketing Components
import { Navigation, Hero, Section, ServiceCard, Footer } from "@yca-software/design-system";
function LandingPage() {
return (
<>
<Navigation />
<Hero
title="Welcome"
description="Your description here"
ctaText="Get Started"
onCtaClick={() => console.log("CTA clicked")}
/>
<Section title="Services">
<ServiceCard
icon={<Icon />}
title="Service Title"
description="Service description"
/>
</Section>
<Footer />
</>
);
}Utility Functions
import { cn, getFlagEmoji } from "@yca-software/design-system";
// Merge Tailwind classes
const className = cn("base-class", condition && "conditional-class");
// Get flag emoji for language code
const flag = getFlagEmoji("en"); // "🇬🇧"
const flag2 = getFlagEmoji("tr"); // "🇹🇷"Available Components
UI Components (shadcn/ui based)
Button- Button component with variants (default, destructive, outline, secondary, ghost, link)Input- Input field componentLabel- Label component for formsCard- Card container component (CardHeader, CardTitle, CardDescription, CardContent, CardFooter)Alert- Alert/notification componentAlertDialog- Alert dialog componentDialog- Modal dialog componentForm- Form components (FormField, FormItem, FormLabel, FormControl, FormMessage, FormDescription)DropdownMenu- Dropdown menu componentAvatar- Avatar componentLink- Link componentScrollArea- Scrollable area componentSeparator- Separator/divider componentSheet- Side sheet componentTable- Table componentTypography- Typography components (Heading, Paragraph)
Marketing Components
Navigation- Marketing site navigationHero- Hero section componentSection- Section wrapper componentServiceCard- Service card componentFooter- Footer component
Utilities
cn- Utility function for merging Tailwind classes (clsx + tailwind-merge)getFlagEmoji- Maps language codes to flag emojis
Detailed Usage Examples
Form Components
import { Form, FormField, FormItem, FormLabel, FormControl, FormMessage, Input, Button } from "@yca-software/design-system";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
const formSchema = z.object({
email: z.string().email("Invalid email"),
password: z.string().min(8, "Password must be at least 8 characters"),
});
function LoginForm() {
const form = useForm({
resolver: zodResolver(formSchema),
defaultValues: { email: "", password: "" },
});
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)}>
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<FormLabel>Email</FormLabel>
<FormControl>
<Input type="email" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit">Submit</Button>
</form>
</Form>
);
}Card Components
import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from "@yca-software/design-system";
function ProductCard() {
return (
<Card>
<CardHeader>
<CardTitle>Product Name</CardTitle>
<CardDescription>Product description goes here</CardDescription>
</CardHeader>
<CardContent>
<p>Product details...</p>
</CardContent>
<CardFooter>
<Button>Add to Cart</Button>
</CardFooter>
</Card>
);
}Dialog and Alert Dialog
import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "@yca-software/design-system";
import { AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogAction, AlertDialogCancel } from "@yca-software/design-system";
// Regular Dialog
<Dialog>
<DialogTrigger asChild>
<Button>Open Dialog</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Dialog Title</DialogTitle>
<DialogDescription>Dialog description</DialogDescription>
</DialogHeader>
{/* Dialog content */}
</DialogContent>
</Dialog>
// Alert Dialog (for confirmations)
<AlertDialog>
<AlertDialogTrigger asChild>
<Button variant="destructive">Delete</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Are you sure?</AlertDialogTitle>
<AlertDialogDescription>
This action cannot be undone.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogAction onClick={handleDelete}>Delete</AlertDialogAction>
<AlertDialogCancel>Cancel</AlertDialogCancel>
</AlertDialogContent>
</AlertDialog>More components will be added as needed. See src/components/ui/ for UI components and src/components/marketing/ for marketing components.
Adding New Components
- Add the component file to:
src/components/ui/for basic UI components (shadcn/ui style)src/components/marketing/for marketing site components- Or create a new subdirectory for component groups
- Export it from
src/components/index.ts(or the appropriate index file likesrc/components/ui/index.tsorsrc/components/marketing/index.ts) - Update this README
Styling
Components use Tailwind CSS (v4) with CSS variables for theming.
Import the canonical theme tokens once in your app’s global CSS:
@import "tailwindcss";
@import "@yca-software/design-system/styles.css";Testing
The component library uses Vitest for unit testing and React Testing Library for component testing.
Running Tests
# Run all tests
pnpm test
# Run tests in watch mode
pnpm test --watch
# Run tests with UI
pnpm test:ui
# Run tests with coverage
pnpm test:coverageWriting Tests
Tests are located alongside components (e.g., button.test.tsx) or in the src/test/ directory.
Example test:
import { describe, it, expect } from "vitest";
import { render, screen } from "../test/test-utils";
import { Button } from "./button";
describe("Button", () => {
it("renders correctly", () => {
render(<Button>Click me</Button>);
expect(screen.getByRole("button")).toBeInTheDocument();
});
});Component Documentation (Storybook)
The component library uses Storybook for interactive component documentation.
Viewing Components
# Start the documentation server
pnpm dev:docs
# Build static documentation
pnpm build:docs
# Preview built documentation
pnpm preview:docsThe documentation will be available at http://localhost:6006 by default.
Writing Stories
Stories are located alongside components (e.g., button.stories.tsx). They use Storybook's API:
import type { Meta, StoryObj } from "@storybook/react";
import { Button } from "./button";
const meta: Meta<typeof Button> = {
title: "UI/Button",
component: Button,
};
export default meta;
type Story = StoryObj<typeof Button>;
export const Default: Story = {
args: {
children: "Click me",
},
};
export const Variants: Story = {
render: () => (
<div className="flex gap-4">
<Button variant="default">Default</Button>
<Button variant="outline">Outline</Button>
</div>
),
};Stories automatically appear in the Storybook sidebar and can be used to:
- Preview components in isolation
- Test different props and variants
- Share component examples with your team
- Document component usage
