DEMO/
├── next/ # Next.js demo app
│ ├── public/ # Static assets
│ │ └── favicon.ico
│ ├── src/app/ # App router
│ │ ├── globals.css # Global styles
│ │ ├── layout.tsx # Root layout
│ │ └── page.tsx # Demo page
│ ├── next.config.js # Next.js config
│ └── package.json # Next.js dependencies
│
└── Library/ # UI Component Library
├── .storybook/ # Storybook config
│ ├── main.ts # Storybook main config
│ └── preview.ts # Storybook preview config
├── src/
│ ├── components/
│ │ └── Button/ # Button component
│ │ ├── Button.tsx # Component logic
│ │ ├── Button.types.ts # Type definitions
│ │ ├── Button.styles.ts # Style logic
│ │ ├── Button.test.tsx # Unit tests
│ │ ├── Button.stories.tsx # Storybook stories
│ │ └── index.ts # Component export
│ ├── styles/
│ │ ├── Button.css # Component CSS
│ │ └── globals.css # Global CSS
│ └── index.ts # Library entry point
├── babel.config.js # Babel config
├── jest.config.js # Jest config
├── jest.setup.js # Jest setup
├── package.json # Library dependencies
├── rollup.config.js # Rollup config
├── tsconfig.json # TypeScript config
└── vite.config.ts # Vite config
- Node.js 18+
- npm 9+
# Clone the repository
git clone https://github.com/your-username/Task.git
cd Task/DEMO
# Install dependencies for both projects
npm install
cd ../Library
npm install
cd DEMO/next
npm run dev
Open http://localhost:3000 to view the demo app.
cd Library
npm run dev
cd Library
npm run storybook
Open http://localhost:6006 to view component documentation.
cd Library
npm test # Run all tests
npm run test:cov # Run tests with coverage
The demo Next.js app is pre-configured to import components directly from the library. Example usage in DEMO/next/src/app/page.tsx:
'use client'
import { Button } from "../../../Library/src";
export default function Home() {
return (
<div className="p-8">
<Button variant="primary">Primary Button</Button>
<Button variant="secondary" className="ml-4">Secondary</Button>
</div>
)
}
Each component follows this pattern:
- Button.tsx - Main component logic
- Button.types.ts - TypeScript interfaces
- Button.styles.ts - Style configuration
- Button.test.tsx - Unit tests
- Button.stories.tsx - Storybook documentation
// Button.tsx
import React from 'react';
import { ButtonProps } from './Button.types';
import { getButtonClasses } from './Button.styles';
export const Button: React.FC<ButtonProps> = ({
variant = 'primary',
size = 'md',
isLoading = false,
children,
...props
}) => {
const buttonClasses = getButtonClasses(variant, size);
return (
<button className={buttonClasses} {...props}>
{isLoading ? 'Loading...' : children}
</button>
);
};
Tests use Jest and React Testing Library:
// Button.test.tsx
import { render, screen } from '@testing-library/react';
import { Button } from './Button';
describe('Button Component', () => {
it('renders primary button by default', () => {
render(<Button>Click</Button>);
expect(screen.getByText('Click')).toHaveClass('sg-button-primary');
});
});
Interactive documentation:
// Button.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './Button';
const meta: Meta<typeof Button> = {
title: 'Components/Button',
component: Button,
};
export default meta;
export const Primary: StoryObj<typeof Button> = {
args: {
children: 'Primary Button',
variant: 'primary'
},
};
cd Library
npm run build
This creates production-ready bundles in:
- dist/cjs/ - CommonJS format
- dist/esm/ - ES Modules format
- dist/types/ - TypeScript declarations
cd DEMO/next
npm run build
- Fork the repository
- Create a feature branch (
git checkout -b feature/your-feature
) - Commit your changes (
git commit -m 'Add some feature'
) - Push to the branch (
git push origin feature/your-feature
) - Open a Pull Request
MIT © [Pouya]