Creates production-ready React components with TypeScript, Tailwind CSS, and testing. USE WHEN user says 'create component', 'build component', 'new component', OR wants to add UI elements.
Creates React components following Maiyuri Bricks project standards.
# Component goes in apps/web/src/components/
apps/web/src/components/ComponentName/
āāā ComponentName.tsx
āāā ComponentName.test.tsx
āāā index.ts
When creating a React component:
Choose component type:
packages/ui/src/apps/web/src/components/Create the component file:
import React from 'react';
import { cn } from '@maiyuri/ui';
interface ComponentNameProps {
className?: string;
children?: React.ReactNode;
}
export const ComponentName: React.FC<ComponentNameProps> = ({
className,
children
}) => {
return (
<div className={cn('base-styles', className)}>
{children}
</div>
);
};
Add to barrel export:
// index.ts
export { ComponentName } from './ComponentName';
export type { ComponentNameProps } from './ComponentName';
Write tests:
import { render, screen } from '@testing-library/react';
import { ComponentName } from './ComponentName';
describe('ComponentName', () => {
it('renders children', () => {
render(<ComponentName>Test</ComponentName>);
expect(screen.getByText('Test')).toBeInTheDocument();
});
});
import { Card, Badge } from '@maiyuri/ui';
import type { Lead } from '@maiyuri/shared';
interface LeadCardProps {
lead: Lead;
onStatusChange?: (status: Lead['status']) => void;
}
export const LeadCard: React.FC<LeadCardProps> = ({ lead, onStatusChange }) => {
const statusColors = {
new: 'default',
follow_up: 'warning',
hot: 'danger',
cold: 'default',
converted: 'success',
lost: 'danger'
} as const;
return (
<Card className="p-4">
<div className="flex justify-between items-start">
<div>
<h3 className="font-semibold">{lead.name}</h3>
<p className="text-sm text-muted">{lead.contact}</p>
</div>
<Badge variant={statusColors[lead.status]}>
{lead.status.replace('_', ' ')}
</Badge>
</div>
</Card>
);
};
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { createLeadSchema, type CreateLeadInput } from '@maiyuri/shared';
import { Button } from '@maiyuri/ui';
export const CreateLeadForm: React.FC<{
onSubmit: (data: CreateLeadInput) => void;
}> = ({ onSubmit }) => {
const { register, handleSubmit, formState: { errors } } = useForm<CreateLeadInput>({
resolver: zodResolver(createLeadSchema)
});
return (
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
<input {...register('name')} placeholder="Lead name" />
{errors.name && <span className="text-red-500">{errors.name.message}</span>}
<Button type="submit">Create Lead</Button>
</form>
);
};
cn() utility for class merging