| name | create-component |
| description | 프로젝트의 shadcn/ui + Tailwind 패턴에 따라 새 React 컴포넌트를 생성합니다. UI 프리미티브(버튼, 다이얼로그 등) 또는 도메인 컴포넌트(ServerMap, Inspector 등)를 새로 만들 때 반드시 이 스킬을 사용하세요. |
새 컴포넌트 생성
$ARGUMENTS 설명을 가진 $0 컴포넌트를 생성합니다.
1. 컴포넌트 유형 결정
UI 프리미티브 (packages/ui/src/components/ui/)
재사용 가능한 일반 UI 컴포넌트(버튼 변형, 다이얼로그, 입력 등):
- shadcn/ui 패턴 준수: Radix UI + CVA + Tailwind
@pinpoint-fe/ui/src/lib/utils의 cn() 사용
- 적절한 경우 Radix Slot을 통한
asChild 지원
- ref 전달을 위한
React.forwardRef 사용
- CVA(class-variance-authority)로 variants 정의
도메인 컴포넌트 (packages/ui/src/components/{DomainName}/)
기능별 컴포넌트(ServerMap, ErrorAnalysis 등):
packages/ui/src/components/ 아래 서브디렉토리 생성
- UI 프리미티브를 조합하여 구성
- 데이터 페칭에 React Query 훅 사용
- 공유 상태에 Jotai 아톰 사용
- 비동기 콘텐츠를 Suspense + ErrorBoundary로 감싸기
2. 기존 예시 읽기
- UI 프리미티브:
packages/ui/src/components/ui/button.tsx 또는 dialog.tsx 읽기
- 도메인 컴포넌트: 타겟과 유사한 기존 도메인 컴포넌트 읽기
3. 컴포넌트 생성
UI 프리미티브 템플릿
import * as React from 'react';
import { cva, type VariantProps } from 'class-variance-authority';
import { cn } from '@pinpoint-fe/ui/src/lib/utils';
const componentVariants = cva('base-classes', {
variants: { variant: { default: '...', outline: '...' }, size: { default: '...', sm: '...' } },
defaultVariants: { variant: 'default', size: 'default' },
});
export interface ComponentProps
extends React.HTMLAttributes<HTMLDivElement>,
VariantProps<typeof componentVariants> {}
const Component = React.forwardRef<HTMLDivElement, ComponentProps>(
({ className, variant, size, ...props }, ref) => (
<div ref={ref} className={cn(componentVariants({ variant, size, className }))} {...props} />
),
);
Component.displayName = 'Component';
export { Component, componentVariants };
도메인 컴포넌트 템플릿
import React, { Suspense } from 'react';
import { ErrorBoundary } from 'react-error-boundary';
import { useTranslation } from 'react-i18next';
import { useAtomValue } from 'jotai';
import { cn } from '@pinpoint-fe/ui/src/lib/utils';
import { someSearchParamAtom } from '@pinpoint-fe/ui/src/atoms';
import { useGetMyData } from '@pinpoint-fe/ui/src/hooks/api';
export interface MyComponentProps {
className?: string;
}
const MyComponentContent = ({ className }: MyComponentProps) => {
const { t } = useTranslation();
const searchParam = useAtomValue(someSearchParamAtom);
const { data } = useGetMyData({ param: searchParam });
if (!data) return null;
return <div className={cn('...', className)}>{/* 렌더링 */}</div>;
};
export const MyComponent = ({ className }: MyComponentProps) => (
<ErrorBoundary fallback={<div>Error</div>}>
<Suspense fallback={<div>Loading...</div>}>
<MyComponentContent className={className} />
</Suspense>
</ErrorBoundary>
);
4. 스타일링 규칙
- Tailwind CSS만 사용 — 인라인 스타일, CSS 모듈 금지
- 테마에는 CSS 변수 사용:
var(--ui-primary), var(--ui-border)
- 모든 className 합성에
cn() 사용
- Tailwind 브레이크포인트로 반응형 디자인
5. 완료
packages/ui/src/components/index.ts (또는 해당 서브디렉토리의 index.ts)에서 컴포넌트 익스포트
yarn build로 TypeScript 오류 없음 확인